From: Nathan Binkert Date: Mon, 6 Jul 2009 22:49:47 +0000 (-0700) Subject: ruby: Import the latest ruby changes from gems. X-Git-Tag: Calvin_Submission~233 X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=92de70b69aaf3f399a855057b556ed198139e5d8;p=gem5.git ruby: Import the latest ruby changes from gems. This was done with an automated process, so there could be things that were done in this tree in the past that didn't make it. One known regression is that atomic memory operations do not seem to work properly anymore. --- diff --git a/src/mem/gems_common/std-includes.hh b/src/mem/gems_common/std-includes.hh index 619214f1d..d6062337f 100644 --- a/src/mem/gems_common/std-includes.hh +++ b/src/mem/gems_common/std-includes.hh @@ -26,6 +26,10 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +/* + * $Id: std-includes.hh,v 3.7 2003/02/24 21:05:24 xu Exp $ + */ + #ifndef INCLUDES_H #define INCLUDES_H diff --git a/src/mem/gems_common/util.cc b/src/mem/gems_common/util.cc index a64da15a6..403be383f 100644 --- a/src/mem/gems_common/util.cc +++ b/src/mem/gems_common/util.cc @@ -30,8 +30,7 @@ * $Id$ */ -#include - +#include "assert.hh" #include "mem/gems_common/util.hh" // Split a string into a head and tail strings on the specified @@ -43,7 +42,7 @@ string string_split(string& str, char split_character) string head = ""; string tail = ""; - unsigned counter = 0; + uint counter = 0; while(counter < str.size()) { if (str[counter] == split_character) { counter++; @@ -91,6 +90,19 @@ float string_to_float(string& str) return ret; } +bool string_to_bool(const string & str) +{ + string lower(str); + for (size_t i=0;i0); Time current_time = g_eventQueue_ptr->getTime(); Time arrival_time = 0; - if (!RANDOMIZATION || (m_randomization == false)) { + if (!RubySystem::getRandomization() || (m_randomization == false)) { // No randomization arrival_time = current_time + delta; @@ -294,7 +296,7 @@ void MessageBuffer::pop() { DEBUG_MSG(QUEUE_COMP,MedPrio,"pop from " + m_name); assert(isReady()); - m_prio_heap.extractMin(); + Time ready_time = m_prio_heap.extractMin().m_time; // record previous size and time so the current buffer size isn't adjusted until next cycle if (m_time_last_time_pop < g_eventQueue_ptr->getTime()) { m_size_at_cycle_start = m_size; @@ -321,13 +323,13 @@ void MessageBuffer::clear() void MessageBuffer::recycle() { - // const int RECYCLE_LATENCY = 3; + // const int RubyConfig::getRecycleLatency() = 3; DEBUG_MSG(QUEUE_COMP,MedPrio,"recycling " + m_name); assert(isReady()); MessageBufferNode node = m_prio_heap.extractMin(); - node.m_time = g_eventQueue_ptr->getTime() + RECYCLE_LATENCY; + node.m_time = g_eventQueue_ptr->getTime() + m_recycle_latency; m_prio_heap.insert(node); - g_eventQueue_ptr->scheduleEventAbsolute(m_consumer_ptr, g_eventQueue_ptr->getTime() + RECYCLE_LATENCY); + g_eventQueue_ptr->scheduleEventAbsolute(m_consumer_ptr, g_eventQueue_ptr->getTime() + m_recycle_latency); } int MessageBuffer::setAndReturnDelayCycles(MsgPtr& message) diff --git a/src/mem/ruby/buffers/MessageBuffer.hh b/src/mem/ruby/buffers/MessageBuffer.hh index b58203a93..3ca6790d0 100644 --- a/src/mem/ruby/buffers/MessageBuffer.hh +++ b/src/mem/ruby/buffers/MessageBuffer.hh @@ -60,6 +60,7 @@ public: // Public Methods static void printConfig(ostream& out) {} + void setRecycleLatency(int recycle_latency) { m_recycle_latency = recycle_latency; } // TRUE if head of queue timestamp <= SystemTime bool isReady() const { @@ -105,6 +106,9 @@ public: void clearStats() { m_not_avail_count = 0; m_msg_counter = 0; } private: + //added by SS + int m_recycle_latency; + // Private Methods int setAndReturnDelayCycles(MsgPtr& message); diff --git a/src/mem/ruby/common/Address.hh b/src/mem/ruby/common/Address.hh index d72fbf38a..b6899d1ac 100644 --- a/src/mem/ruby/common/Address.hh +++ b/src/mem/ruby/common/Address.hh @@ -1,3 +1,4 @@ + /* * Copyright (c) 1999 Mark D. Hill and David A. Wood * All rights reserved. @@ -26,12 +27,16 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +/* + * $Id$ + */ + #ifndef ADDRESS_H #define ADDRESS_H #include #include "mem/ruby/common/Global.hh" -#include "mem/ruby/config/RubyConfig.hh" +#include "mem/ruby/system/System.hh" #include "mem/ruby/system/NodeID.hh" #include "mem/ruby/system/MachineID.hh" @@ -63,17 +68,16 @@ public: physical_address_t maskHighOrderBits(int number) const; physical_address_t shiftLowOrderBits(int number) const; physical_address_t getLineAddress() const - { return bitSelect(RubyConfig::dataBlockBits(), ADDRESS_WIDTH); } + { return bitSelect(RubySystem::getBlockSizeBits(), ADDRESS_WIDTH); } physical_address_t getOffset() const - { return bitSelect(0, RubyConfig::dataBlockBits()-1); } + { return bitSelect(0, RubySystem::getBlockSizeBits()-1); } - void makeLineAddress() { m_address = maskLowOrderBits(RubyConfig::dataBlockBits()); } + void makeLineAddress() { m_address = maskLowOrderBits(RubySystem::getBlockSizeBits()); } // returns the next stride address based on line address void makeNextStrideAddress( int stride) { - m_address = maskLowOrderBits(RubyConfig::dataBlockBits()) - + RubyConfig::dataBlockBytes()*stride; + m_address = maskLowOrderBits(RubySystem::getBlockSizeBits()) + + RubySystem::getBlockSizeBytes()*stride; } - void makePageAddress() { m_address = maskLowOrderBits(RubyConfig::pageSizeBits()); } int getBankSetNum() const; int getBankSetDist() const; @@ -103,6 +107,7 @@ private: inline Address line_address(const Address& addr) { Address temp(addr); temp.makeLineAddress(); return temp; } +/* inline Address next_stride_address(const Address& addr, int stride) { Address temp = addr; @@ -110,9 +115,7 @@ Address next_stride_address(const Address& addr, int stride) { temp.setAddress(temp.maskHighOrderBits(ADDRESS_WIDTH-RubyConfig::memorySizeBits())); // surpress wrap-around problem return temp; } - -inline -Address page_address(const Address& addr) { Address temp(addr); temp.makePageAddress(); return temp; } +*/ // Output operator declaration ostream& operator<<(ostream& out, const Address& obj); @@ -202,17 +205,19 @@ physical_address_t Address::shiftLowOrderBits(int number) const inline integer_t Address::memoryModuleIndex() const { - integer_t index = bitSelect(RubyConfig::dataBlockBits()+RubyConfig::memoryBits(), ADDRESS_WIDTH); + integer_t index = bitSelect(RubySystem::getBlockSizeBits()+RubySystem::getMemorySizeBits(), ADDRESS_WIDTH); assert (index >= 0); + /* if (index >= RubyConfig::memoryModuleBlocks()) { - cerr << " memoryBits: " << RubyConfig::memoryBits() << " memorySizeBits: " << RubyConfig::memorySizeBits() - << " Address: " << "[" << hex << "0x" << m_address << "," << " line 0x" << maskLowOrderBits(RubyConfig::dataBlockBits()) << dec << "]" << flush + cerr << " memoryBits: " << RubySystem::getMemorySizeBits() << " memorySizeBits: " << RubySystem::getMemorySizeBits() + << " Address: " << "[" << hex << "0x" << m_address << "," << " line 0x" << maskLowOrderBits(RubySystem::getBlockSizeBits()) << dec << "]" << flush << "error: limit exceeded. " << - " dataBlockBits: " << RubyConfig::dataBlockBits() << + " getDataBlockBits: " << RubySystem::getBlockSizeBits() << " memoryModuleBlocks: " << RubyConfig::memoryModuleBlocks() << " index: " << index << endl; } assert (index < RubyConfig::memoryModuleBlocks()); + */ return index; // Index indexHighPortion = address.bitSelect(MEMORY_SIZE_BITS-1, PAGE_SIZE_BITS+NUMBER_OF_MEMORY_MODULE_BITS); @@ -239,7 +244,7 @@ ADDRESS_WIDTH MEMORY_SIZE_BITS PAGE_SIZE_BITS DATA_BLOCK_BITS inline void Address::print(ostream& out) const { - out << "[" << hex << "0x" << m_address << "," << " line 0x" << maskLowOrderBits(RubyConfig::dataBlockBits()) << dec << "]" << flush; + out << "[" << hex << "0x" << m_address << "," << " line 0x" << maskLowOrderBits(RubySystem::getBlockSizeBits()) << dec << "]" << flush; } class Address; diff --git a/src/mem/ruby/common/Consumer.hh b/src/mem/ruby/common/Consumer.hh index 34cd7864c..4a14ca20f 100644 --- a/src/mem/ruby/common/Consumer.hh +++ b/src/mem/ruby/common/Consumer.hh @@ -53,7 +53,8 @@ public: virtual ~Consumer() { } // Public Methods - pure virtual methods - void triggerWakeup() { Time time = g_eventQueue_ptr->getTime(); if (m_last_wakeup != time) { wakeup(); m_last_wakeup = time; }} + // void triggerWakeup() { Time time = g_eventQueue_ptr->getTime(); if (m_last_wakeup != time) { wakeup(); m_last_wakeup = time; }} + void triggerWakeup(RubyEventQueue * eventQueue) { Time time = eventQueue->getTime(); if (m_last_wakeup != time) { wakeup(); m_last_wakeup = time; }} virtual void wakeup() = 0; virtual void print(ostream& out) const = 0; const Time& getLastScheduledWakeup() const { return m_last_scheduled_wakeup; } diff --git a/src/mem/ruby/common/DataBlock.cc b/src/mem/ruby/common/DataBlock.cc index ce72bc7f4..5e6b8338e 100644 --- a/src/mem/ruby/common/DataBlock.cc +++ b/src/mem/ruby/common/DataBlock.cc @@ -1,91 +1,16 @@ -/* - * Copyright (c) 1999-2008 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. - */ - -/* - * $Id$ - */ - #include "mem/ruby/common/DataBlock.hh" -DataBlock::DataBlock() -{ - if (DATA_BLOCK || XACT_MEMORY) { - m_data.setSize(RubyConfig::dataBlockBytes()); - } - clear(); -} - -DataBlock::~DataBlock() -{ - -} - -void DataBlock::clear() -{ - int size = m_data.size(); - for (int i = 0; i < size; i++) { - m_data[i] = 0; - } -} - -bool DataBlock::equal(const DataBlock& obj) const +DataBlock & +DataBlock::operator=(const DataBlock & obj) { - bool value = true; - int size = m_data.size(); - for (int i = 0; i < size; i++) { - value = value && (m_data[i] == obj.m_data[i]); - } - return value; -} - -void DataBlock::print(ostream& out) const -{ - int size = m_data.size(); - for (int i = 0; i < size; i+=4) { - out << hex << *((uint32*)(&(m_data[i]))) << " "; - } - out << dec << "]" << flush; -} - -uint8 DataBlock::getByte(int whichByte) const -{ - if (DATA_BLOCK || XACT_MEMORY) { - return m_data[whichByte]; + if (this == &obj) { + // assert(false); } else { - return 0; - } -} - -void DataBlock::setByte(int whichByte, uint8 data) -{ - if (DATA_BLOCK || XACT_MEMORY) { - m_data[whichByte] = data; + if (!m_alloc) + m_data = new uint8[RubySystem::getBlockSizeBytes()]; + memcpy(m_data, obj.m_data, RubySystem::getBlockSizeBytes()); + m_alloc = true; } + return *this; } - diff --git a/src/mem/ruby/common/DataBlock.hh b/src/mem/ruby/common/DataBlock.hh index 8711cb740..2a0811f76 100644 --- a/src/mem/ruby/common/DataBlock.hh +++ b/src/mem/ruby/common/DataBlock.hh @@ -31,29 +31,41 @@ #define DATABLOCK_H #include "mem/ruby/common/Global.hh" -#include "mem/ruby/config/RubyConfig.hh" +#include "mem/ruby/system/System.hh" #include "mem/gems_common/Vector.hh" class DataBlock { -public: + public: // Constructors - DataBlock(); + DataBlock() {alloc();} + DataBlock(const DataBlock & cp) { + m_data = new uint8[RubySystem::getBlockSizeBytes()]; + memcpy(m_data, cp.m_data, RubySystem::getBlockSizeBytes()); + m_alloc = true; + } // Destructor - ~DataBlock(); + ~DataBlock() { if(m_alloc) delete [] m_data;} + + DataBlock& operator=(const DataBlock& obj); // Public Methods + void assign(uint8* data); + void clear(); uint8 getByte(int whichByte) const; + const uint8* getData(int offset, int len) const; void setByte(int whichByte, uint8 data); + void setData(uint8* data, int offset, int len); + void copyPartial(const DataBlock & dblk, int offset, int len); bool equal(const DataBlock& obj) const; void print(ostream& out) const; private: - // Private Methods - + void alloc(); // Data Members (m_ prefix) - Vector m_data; + uint8* m_data; + bool m_alloc; }; // Output operator declaration @@ -61,6 +73,78 @@ ostream& operator<<(ostream& out, const DataBlock& obj); bool operator==(const DataBlock& obj1, const DataBlock& obj2); +// inline functions for speed + +inline +void DataBlock::assign(uint8* data) +{ + delete [] m_data; + m_data = data; + m_alloc = false; +} + +inline +void DataBlock::alloc() +{ + m_data = new uint8[RubySystem::getBlockSizeBytes()]; + m_alloc = true; + clear(); +} + +inline +void DataBlock::clear() +{ + memset(m_data, 0, RubySystem::getBlockSizeBytes()); +} + +inline +bool DataBlock::equal(const DataBlock& obj) const +{ + return !memcmp(m_data, obj.m_data, RubySystem::getBlockSizeBytes()); +} + +inline +void DataBlock::print(ostream& out) const +{ + int size = RubySystem::getBlockSizeBytes(); + out << "[ "; + for (int i = 0; i < size; i+=4) { + out << hex << *((uint32*)(&(m_data[i]))) << " "; + } + out << dec << "]" << flush; +} + +inline +uint8 DataBlock::getByte(int whichByte) const +{ + return m_data[whichByte]; +} + +inline +const uint8* DataBlock::getData(int offset, int len) const +{ + assert(offset + len <= RubySystem::getBlockSizeBytes()); + return &m_data[offset]; +} + +inline +void DataBlock::setByte(int whichByte, uint8 data) +{ + m_data[whichByte] = data; +} + +inline +void DataBlock::setData(uint8* data, int offset, int len) +{ + assert(offset + len <= RubySystem::getBlockSizeBytes()); + memcpy(&m_data[offset], data, len); +} + +inline +void DataBlock::copyPartial(const DataBlock & dblk, int offset, int len) +{ + setData(&dblk.m_data[offset], offset, len); +} // ******************* Definitions ******************* diff --git a/src/mem/ruby/common/Debug.cc b/src/mem/ruby/common/Debug.cc index 02f4069ee..c1a6e16d0 100644 --- a/src/mem/ruby/common/Debug.cc +++ b/src/mem/ruby/common/Debug.cc @@ -38,36 +38,28 @@ #include "mem/ruby/common/Global.hh" #include "mem/ruby/common/Debug.hh" #include "mem/ruby/eventqueue/RubyEventQueue.hh" +#include "mem/gems_common/util.hh" class Debug; extern Debug* g_debug_ptr; std::ostream * debug_cout_ptr; -struct DebugComponentData +bool Debug::m_protocol_trace = false; + +// component character list +const char DEFINE_COMP_CHAR[] = { - const char *desc; - const char ch; +#undef DEFINE_COMP +#define DEFINE_COMP(component, character, description) character, +#include "Debug.def" }; -// component character list -DebugComponentData debugComponents[] = +// component description list +const char* DEFINE_COMP_DESCRIPTION[] = { - {"System", 's' }, - {"Node", 'N' }, - {"Queue", 'q' }, - {"Event Queue", 'e' }, - {"Network", 'n' }, - {"Sequencer", 'S' }, - {"Tester", 't' }, - {"Generated", 'g' }, - {"SLICC", 'l' }, - {"Network Queues", 'Q' }, - {"Time", 'T' }, - {"Network Internals", 'i' }, - {"Store Buffer", 'b' }, - {"Cache", 'c' }, - {"Predictor", 'p' }, - {"Allocator", 'a' }, +#undef DEFINE_COMP +#define DEFINE_COMP(component, character, description) description, +#include "Debug.def" }; extern "C" void changeDebugVerbosity(VerbosityLevel vb); @@ -83,6 +75,32 @@ void changeDebugFilter(int filter) g_debug_ptr->setFilter(filter); } +Debug::Debug() +{ + m_verbosityLevel = No_Verb; + m_starting_cycle = ~0; + clearFilter(); + debug_cout_ptr = &cout; +} + +Debug::Debug( const string & name, const vector & argv ) +{ + for (size_t i=0;i #include -#include "config/ruby_debug.hh" -#include "mem/ruby/common/Global.hh" - extern std::ostream * debug_cout_ptr; // component enumeration enum DebugComponents { - SYSTEM_COMP, - NODE_COMP, - QUEUE_COMP, - EVENTQUEUE_COMP, - NETWORK_COMP, - SEQUENCER_COMP, - TESTER_COMP, - GENERATED_COMP, - SLICC_COMP, - NETWORKQUEUE_COMP, - TIME_COMP, - NETWORK_INTERNALS_COMP, - STOREBUFFER_COMP, - CACHE_COMP, - PREDICTOR_COMP, - ALLOCATOR_COMP, - NUMBER_OF_COMPS +#undef DEFINE_COMP +#define DEFINE_COMP(component, character, description) component, +#include "Debug.def" + NUMBER_OF_COMPS }; enum PriorityLevel {HighPrio, MedPrio, LowPrio}; @@ -70,6 +54,8 @@ enum VerbosityLevel {No_Verb, Low_Verb, Med_Verb, High_Verb}; class Debug { public: // Constructors + Debug(); + Debug( const string & name, const vector & argv ); Debug( const char *filterString, const char *verboseString, Time filterStartTime, const char *filename ); @@ -77,6 +63,7 @@ public: ~Debug(); // Public Methods + static bool getProtocolTrace() { return m_protocol_trace; } bool validDebug(int module, PriorityLevel priority); void printVerbosity(ostream& out) const; void setVerbosity(VerbosityLevel vb); @@ -108,6 +95,7 @@ private: Debug& operator=(const Debug& obj); // Data Members (m_ prefix) + static bool m_protocol_trace; VerbosityLevel m_verbosityLevel; int m_filter; Time m_starting_cycle; @@ -155,7 +143,7 @@ const bool ASSERT_FLAG = true; << __PRETTY_FUNCTION__ << " in "\ << __FILE__ << ":"\ << __LINE__ << endl << flush;\ - if(isatty(STDERR_FILENO)) {\ + if(isatty(STDIN_FILENO)) {\ cerr << "At this point you might want to attach a debug to ";\ cerr << "the running and get to the" << endl;\ cerr << "crash site; otherwise press enter to continue" << endl;\ @@ -176,7 +164,7 @@ const bool ASSERT_FLAG = true; << __PRETTY_FUNCTION__ << " in "\ << __FILE__ << ":"\ << __LINE__ << endl << flush;\ - if(isatty(STDERR_FILENO)) {\ + if(isatty(STDIN_FILENO)) {\ cerr << "press enter to continue" << endl;\ cerr << "PID: " << getpid();\ cerr << endl << flush; \ @@ -303,5 +291,5 @@ const bool ASSERT_FLAG = true; }\ } -#endif // __MEM_RUBY_DEBUG_HH__ +#endif //DEBUG_H diff --git a/src/mem/ruby/common/Driver.hh b/src/mem/ruby/common/Driver.hh index 38bdbbf91..db8279fa5 100644 --- a/src/mem/ruby/common/Driver.hh +++ b/src/mem/ruby/common/Driver.hh @@ -27,6 +27,13 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +/* + * $Id$ + * + * Description: + * + */ + #ifndef DRIVER_H #define DRIVER_H @@ -34,7 +41,6 @@ #include "mem/ruby/common/Consumer.hh" #include "mem/ruby/system/NodeID.hh" #include "mem/protocol/CacheRequestType.hh" -#include "mem/packet.hh" class RubySystem; class SubBlock; @@ -52,10 +58,15 @@ public: // Public Methods virtual void get_network_config() {} - virtual void hitCallback(Packet* pkt) = 0; + virtual void dmaHitCallback() = 0; + virtual void hitCallback(NodeID proc, SubBlock& data, CacheRequestType type, int thread) = 0; // Called by sequencer + virtual void conflictCallback(NodeID proc, SubBlock& data, CacheRequestType type, int thread) { assert(0) }; // Called by sequencer virtual integer_t getInstructionCount(int procID) const { return 1; } virtual integer_t getCycleCount(int procID) const { return 1; } - + virtual void addThreadDependency(int procID, int requestor_thread, int conflict_thread) const { assert(0);} + virtual int inTransaction(int procID, int thread ) const{ + cout << "Driver.hh inTransaction " << endl; +return false; } //called by Sequencer virtual void printDebug(){} //called by Sequencer virtual void printStats(ostream& out) const = 0; @@ -63,6 +74,8 @@ public: virtual void printConfig(ostream& out) const = 0; + //virtual void abortCallback(NodeID proc){} + virtual integer_t readPhysicalMemory(int procID, physical_address_t address, int len ){ ASSERT(0); return 0; } diff --git a/src/mem/ruby/common/Global.hh b/src/mem/ruby/common/Global.hh index 205b2bcb2..591ffed1e 100644 --- a/src/mem/ruby/common/Global.hh +++ b/src/mem/ruby/common/Global.hh @@ -32,9 +32,10 @@ * * */ -#ifndef __MEM_RUBY_GLOBAL_HH__ -#define __MEM_RUBY_GLOBAL_HH__ +#ifndef GLOBAL_H +#define GLOBAL_H +/* #ifdef SINGLE_LEVEL_CACHE const bool TWO_LEVEL_CACHE = false; #define L1I_CACHE_MEMBER_VARIABLE m_L1Cache_cacheMemory_vec[m_version] // currently all protocols require L1s == nodes @@ -60,24 +61,11 @@ const bool TWO_LEVEL_CACHE = true; #define DIRECTORY_MEMBER_VARIABLE m_Directory_directory_vec[m_version] #define TBE_TABLE_MEMBER_VARIABLE m_L1Cache_TBEs_vec[m_version] -typedef unsigned char uint8; -typedef unsigned int uint32; -typedef unsigned long long uint64; - -typedef signed char int8; -typedef int int32; -typedef long long int64; - -typedef long long integer_t; -typedef unsigned long long uinteger_t; +*/ -typedef int64 Time; -typedef uint64 physical_address_t; -typedef uint64 la_t; -typedef uint64 pa_t; -typedef integer_t simtime_t; // external includes for all classes +#include "mem/ruby/common/TypeDefines.hh" #include "mem/gems_common/std-includes.hh" #include "mem/ruby/common/Debug.hh" @@ -85,6 +73,7 @@ typedef integer_t simtime_t; typedef Time LogicalTime; typedef int64 Index; // what the address bit ripper returns typedef int word; // one word of a cache line +typedef unsigned int uint; typedef int SwitchID; typedef int LinkID; @@ -105,5 +94,5 @@ extern inline int max_tokens() } -#endif // __MEM_RUBY_GLOBAL_HH__ +#endif //GLOBAL_H diff --git a/src/mem/ruby/common/Set.cc b/src/mem/ruby/common/Set.cc index 4cb40a246..6f01c4043 100644 --- a/src/mem/ruby/common/Set.cc +++ b/src/mem/ruby/common/Set.cc @@ -40,6 +40,7 @@ // set sizes #include "mem/ruby/common/Set.hh" +#include "mem/ruby/system/System.hh" #include "mem/ruby/config/RubyConfig.hh" #if __amd64__ || __LP64__ @@ -51,7 +52,7 @@ Set::Set() { m_p_nArray = NULL; - setSize(RubyConfig::numberOfProcessors()); + setSize(RubySystem::getNumberOfSequencers()); } // copy constructor @@ -511,7 +512,7 @@ void Set::setSize(int size) #endif // __32BITS__ // decide whether to use dynamic or static alloction - if(m_nArrayLen<=NUMBER_WORDS_PER_SET) { // constant defined in RubyConfig.h + if(m_nArrayLen<=NUMBER_WORDS_PER_SET) { // constant defined in RubyConfig.hh // its OK to use the static allocation, and it will // probably be faster (as m_nArrayLen is already in the // cache and they will probably share the same cache line) @@ -560,7 +561,7 @@ void Set::print(ostream& out) const return; } char buff[24]; - out << "[Set 0x "; + out << "[Set (" << m_nSize << ") 0x "; for (int i=m_nArrayLen-1; i>=0; i--) { #ifdef __32BITS__ sprintf(buff,"%08X ",m_p_nArray[i]); diff --git a/src/mem/ruby/common/SubBlock.cc b/src/mem/ruby/common/SubBlock.cc index 568d3106a..de40e3f7d 100644 --- a/src/mem/ruby/common/SubBlock.cc +++ b/src/mem/ruby/common/SubBlock.cc @@ -42,16 +42,6 @@ SubBlock::SubBlock(const Address& addr, int size) } } -SubBlock::SubBlock(const Address& addr, const Address& logicalAddress, int size) -{ - m_address = addr; - m_logicalAddress = logicalAddress; - setSize(size); - for(int i=0; i= m_address.getAddress()) && (addr.getAddress() < (m_address.getAddress()+getSize()))); } - // uint8 getByte(const Address& addr) { return m_data[addr.getAddress() - m_address.getAddress()]; } void internalMergeTo(DataBlock& data) const; void internalMergeFrom(const DataBlock& data); // Data Members (m_ prefix) Address m_address; - Address m_logicalAddress; - Vector m_data; + Vector m_data; }; // Output operator declaration diff --git a/src/mem/ruby/common/TypeDefines.hh b/src/mem/ruby/common/TypeDefines.hh new file mode 100644 index 000000000..97b3cd8a4 --- /dev/null +++ b/src/mem/ruby/common/TypeDefines.hh @@ -0,0 +1,23 @@ + +#ifndef TYPEDEFINES_H +#define TYPEDEFINES_H + + +typedef unsigned char uint8; +typedef unsigned int uint32; +typedef unsigned long long uint64; + +typedef signed char int8; +typedef int int32; +typedef long long int64; + +typedef long long integer_t; +typedef unsigned long long uinteger_t; + +typedef int64 Time; +typedef uint64 physical_address_t; +typedef uint64 la_t; +typedef uint64 pa_t; +typedef integer_t simtime_t; + +#endif diff --git a/src/mem/ruby/config/MI_example-homogeneous.rb b/src/mem/ruby/config/MI_example-homogeneous.rb new file mode 100644 index 000000000..8c2eef009 --- /dev/null +++ b/src/mem/ruby/config/MI_example-homogeneous.rb @@ -0,0 +1,64 @@ +#!/usr/bin/ruby +# +# Creates a homogeneous CMP system with a single unified cache per +# core and a crossbar network. Uses the default parameters listed +# below, which can be overridden if a wrapper script sets the hash +# libruby_args. +# + +require "cfg.rb" + +# default values + +num_cores = 16 +L1_CACHE_SIZE_KB = 32 +L1_CACHE_ASSOC = 8 +L1_CACHE_LATENCY = "auto" +num_memories = 2 +memory_size_mb = 1024 +NUM_DMA = 1 + +# check for overrides + +for i in 0..$*.size-1 do + if $*[i] == "-p" + num_cores = $*[i+1].to_i + i = i+1 + elsif $*[i] == "-m" + num_memories = $*[i+1].to_i + i = i+1 + elsif $*[i] == "-s" + memory_size_mb = $*[i+1].to_i + i = i + 1 + end +end + +net_ports = Array.new +iface_ports = Array.new + +num_cores.times { |n| + cache = SetAssociativeCache.new("l1u_"+n.to_s, L1_CACHE_SIZE_KB, L1_CACHE_LATENCY, L1_CACHE_ASSOC, "PSEUDO_LRU") + sequencer = Sequencer.new("Sequencer_"+n.to_s, cache, cache) + iface_ports << sequencer + net_ports << MI_example_CacheController.new("L1CacheController_"+n.to_s, + "L1Cache", + [cache], + sequencer) +} +num_memories.times { |n| + directory = DirectoryMemory.new("DirectoryMemory_"+n.to_s, memory_size_mb/num_memories) + memory_control = MemoryControl.new("MemoryControl_"+n.to_s) + net_ports << MI_example_DirectoryController.new("DirectoryController_"+n.to_s, + "Directory", + directory, memory_control) +} +NUM_DMA.times { |n| + dma_sequencer = DMASequencer.new("DMASequencer_"+n.to_s) + iface_ports << dma_sequencer + net_ports << DMAController.new("DMAController_"+n.to_s, "DMA", dma_sequencer) +} + +topology = CrossbarTopology.new("theTopology", net_ports) +on_chip_net = Network.new("theNetwork", topology) + +RubySystem.init(iface_ports, on_chip_net) diff --git a/src/mem/ruby/config/RubyConfig.cc b/src/mem/ruby/config/RubyConfig.cc index fe58a74d3..987a3d81d 100644 --- a/src/mem/ruby/config/RubyConfig.cc +++ b/src/mem/ruby/config/RubyConfig.cc @@ -36,135 +36,191 @@ * */ -#include "config/ruby_debug.hh" #include "mem/ruby/config/RubyConfig.hh" -#include "mem/protocol/protocol_name.hh" +//#include "mem/protocol/protocol_name.hh" #include "mem/gems_common/util.hh" -#include "mem/protocol/Protocol.hh" + +#define CONFIG_DEF_FILE "mem/ruby/config/config.hh" + +#define ERROR_MSG(MESSAGE)\ +{\ + cerr << "Fatal Error: in fn "\ + << __PRETTY_FUNCTION__ << " in "\ + << __FILE__ << ":"\ + << __LINE__ << ": "\ + << (MESSAGE) << endl << flush;\ + abort();\ +} + +// declare all configuration variables +#define PARAM_BOOL( NAME, DEFAULT_VALUE, CUSTOM_ACCESSOR ) \ + bool RubyConfig::m_##NAME = DEFAULT_VALUE; +#define PARAM_STRING( NAME, DEFAULT_VALUE, CUSTOM_ACCESSOR ) \ + const char* RubyConfig::m_##NAME = DEFAULT_VALUE; +#define PARAM_ULONG( NAME, DEFAULT_VALUE, CUSTOM_ACCESSOR ) \ + uint64 RubyConfig::m_##NAME = DEFAULT_VALUE; +#define PARAM( NAME, DEFAULT_VALUE, CUSTOM_ACCESSOR ) \ + int RubyConfig::m_##NAME = DEFAULT_VALUE; +#define PARAM_ARRAY( NAME, TYPE, DEFAULT_ARRAY_SIZE, DEFAULT_VALUE, CUSTOM_ACCESSOR ) \ + TYPE* RubyConfig::m_##NAME = NULL; +#define PARAM_ARRAY2D( NAME, TYPE, D1_DEFAULT_ARRAY_SIZE, D2_DEFAULT_ARRAY_SIZE, DEFAULT_VALUE, CUSTOM_ACCESSOR ) \ + TYPE** RubyConfig::m_##NAME = NULL; +#define PARAM_ARRAY3D( NAME, TYPE, D1_DEFAULT_ARRAY_SIZE, D2_DEFAULT_ARRAY_SIZE, D3_DEFAULT_ARRAY_SIZE, DEFAULT_VALUE, CUSTOM_ACCESSOR ) \ + TYPE*** RubyConfig::m_##NAME = NULL; +#include CONFIG_DEF_FILE +#undef PARAM_BOOL +#undef PARAM_STRING +#undef PARAM_ULONG +#undef PARAM +#undef PARAM_ARRAY +#undef PARAM_ARRAY2D +#undef PARAM_ARRAY3D #define CHECK_POWER_OF_2(N) { if (!is_power_of_2(N)) { ERROR_MSG(#N " must be a power of 2."); }} #define CHECK_ZERO(N) { if (N != 0) { ERROR_MSG(#N " must be zero at initialization."); }} #define CHECK_NON_ZERO(N) { if (N == 0) { ERROR_MSG(#N " must be non-zero."); }} +uint32 RubyConfig::m_data_block_mask; + +void RubyConfig::reset() +{ + #define PARAM_BOOL( NAME, DEFAULT_VALUE, CUSTOM_ACCESSOR ) \ + m_##NAME = DEFAULT_VALUE; +#define PARAM_STRING( NAME, DEFAULT_VALUE, CUSTOM_ACCESSOR ) \ + m_##NAME = DEFAULT_VALUE; +#define PARAM_ULONG( NAME, DEFAULT_VALUE, CUSTOM_ACCESSOR ) \ + m_##NAME = DEFAULT_VALUE; +#define PARAM( NAME, DEFAULT_VALUE, CUSTOM_ACCESSOR ) \ + m_##NAME = DEFAULT_VALUE; +#define PARAM_ARRAY( NAME, TYPE, DEFAULT_ARRAY_SIZE, DEFAULT_VALUE, CUSTOM_ACCESSOR ) \ + m_##NAME = new TYPE[DEFAULT_ARRAY_SIZE]; \ + for (int i=0; i= g_PROCS_PER_CHIP); // obviously can't have less processors than procs/chip - g_NUM_CHIPS = g_NUM_PROCESSORS/g_PROCS_PER_CHIP; - ASSERT(g_NUM_L2_BANKS >= g_NUM_CHIPS); // cannot have a single L2cache across multiple chips - - g_NUM_L2_BANKS_PER_CHIP = g_NUM_L2_BANKS/g_NUM_CHIPS; - - ASSERT(L2_CACHE_NUM_SETS_BITS > log_int(g_NUM_L2_BANKS_PER_CHIP)); // cannot have less than one set per bank - L2_CACHE_NUM_SETS_BITS = L2_CACHE_NUM_SETS_BITS - log_int(g_NUM_L2_BANKS_PER_CHIP); - - if (g_NUM_CHIPS > g_NUM_MEMORIES) { - g_NUM_MEMORIES_PER_CHIP = 1; // some chips have a memory, others don't + CHECK_ZERO(m_MEMORY_SIZE_BITS); + CHECK_ZERO(m_NUM_PROCESSORS_BITS); + CHECK_ZERO(m_NUM_CHIP_BITS); + CHECK_ZERO(m_NUM_L2_BANKS_BITS); + CHECK_ZERO(m_NUM_MEMORIES_BITS); + CHECK_ZERO(m_PROCS_PER_CHIP_BITS); + CHECK_ZERO(m_NUM_L2_BANKS_PER_CHIP); + CHECK_ZERO(m_NUM_L2_BANKS_PER_CHIP_BITS); + CHECK_ZERO(m_NUM_MEMORIES_BITS); + CHECK_ZERO(m_MEMORY_MODULE_BLOCKS); + CHECK_ZERO(m_MEMORY_MODULE_BITS); + CHECK_ZERO(m_NUM_MEMORIES_PER_CHIP); + + CHECK_POWER_OF_2(m_MemorySizeBytes); + CHECK_POWER_OF_2(m_NUM_PROCESSORS); + CHECK_POWER_OF_2(m_NUM_L2_BANKS); + CHECK_POWER_OF_2(m_NUM_MEMORIES); + CHECK_POWER_OF_2(m_ProcsPerChip); + + assert(m_NUM_PROCESSORS >= m_ProcsPerChip); // obviously can't have less processors than procs/chip + m_NUM_CHIPS = m_NUM_PROCESSORS/m_ProcsPerChip; + assert(m_NUM_L2_BANKS >= m_NUM_CHIPS); // cannot have a single L2cache across multiple chips + + m_NUM_L2_BANKS_PER_CHIP = m_NUM_L2_BANKS/m_NUM_CHIPS; + + if (m_NUM_CHIPS > m_NUM_MEMORIES) { + m_NUM_MEMORIES_PER_CHIP = 1; // some chips have a memory, others don't } else { - g_NUM_MEMORIES_PER_CHIP = g_NUM_MEMORIES/g_NUM_CHIPS; + m_NUM_MEMORIES_PER_CHIP = m_NUM_MEMORIES/m_NUM_CHIPS; } - g_NUM_CHIP_BITS = log_int(g_NUM_CHIPS); - g_MEMORY_SIZE_BITS = log_int(g_MEMORY_SIZE_BYTES); - g_DATA_BLOCK_BITS = log_int(g_DATA_BLOCK_BYTES); - g_PAGE_SIZE_BITS = log_int(g_PAGE_SIZE_BYTES); - g_NUM_PROCESSORS_BITS = log_int(g_NUM_PROCESSORS); - g_NUM_L2_BANKS_BITS = log_int(g_NUM_L2_BANKS); - g_NUM_L2_BANKS_PER_CHIP_BITS = log_int(g_NUM_L2_BANKS_PER_CHIP); - g_NUM_MEMORIES_BITS = log_int(g_NUM_MEMORIES); - g_PROCS_PER_CHIP_BITS = log_int(g_PROCS_PER_CHIP); - - g_MEMORY_MODULE_BITS = g_MEMORY_SIZE_BITS - g_DATA_BLOCK_BITS - g_NUM_MEMORIES_BITS; - g_MEMORY_MODULE_BLOCKS = (int64(1) << g_MEMORY_MODULE_BITS); - - if ((!Protocol::m_CMP) && (g_PROCS_PER_CHIP > 1)) { - ERROR_MSG("Non-CMP protocol should set g_PROCS_PER_CHIP to 1"); - } + m_NUM_CHIP_BITS = log_int(m_NUM_CHIPS); + m_MEMORY_SIZE_BITS = log_int(m_MemorySizeBytes); - // Randomize the execution - srandom(g_RANDOM_SEED); -} + m_data_block_mask = ~ (~0 << m_DATA_BLOCK_BITS); -int RubyConfig::L1CacheNumToL2Base(NodeID L1CacheNum) -{ - return L1CacheNum/g_PROCS_PER_CHIP; + m_NUM_PROCESSORS_BITS = log_int(m_NUM_PROCESSORS); + m_NUM_L2_BANKS_BITS = log_int(m_NUM_L2_BANKS); + m_NUM_L2_BANKS_PER_CHIP_BITS = log_int(m_NUM_L2_BANKS_PER_CHIP); + m_NUM_MEMORIES_BITS = log_int(m_NUM_MEMORIES); + m_PROCS_PER_CHIP_BITS = log_int(m_ProcsPerChip); + + m_MEMORY_MODULE_BITS = m_MEMORY_SIZE_BITS - m_DATA_BLOCK_BITS - m_NUM_MEMORIES_BITS; + m_MEMORY_MODULE_BLOCKS = (int64(1) << m_MEMORY_MODULE_BITS); + + */ + + // Randomize the execution + // srandom(m_RandomSeed); } static void print_parameters(ostream& out) { -#define PARAM(NAME) { out << #NAME << ": " << NAME << endl; } -#define PARAM_UINT(NAME) { out << #NAME << ": " << NAME << endl; } -#define PARAM_ULONG(NAME) { out << #NAME << ": " << NAME << endl; } -#define PARAM_BOOL(NAME) { out << #NAME << ": " << bool_to_string(NAME) << endl; } -#define PARAM_DOUBLE(NAME) { out << #NAME << ": " << NAME << endl; } -#define PARAM_STRING(NAME) { assert(NAME != NULL); out << #NAME << ": " << string(NAME) << endl; } -#define PARAM_ARRAY(PTYPE, NAME, ARRAY_SIZE) \ - { \ - out << #NAME << ": ("; \ - for (int i = 0; i < ARRAY_SIZE; i++) { \ - if (i != 0) { \ - out << ", "; \ - } \ - out << NAME[i]; \ - } \ - out << ")" << endl; \ - } \ - - -#include "mem/ruby/config/config.hh" +#define print_true(NAME) +#define print_false(NAME) \ + out << #NAME << ": " << RubyConfig::get##NAME () << endl + +#define PARAM(NAME, DEFAULT_VALUE, CUSTOM_ACCESSOR) { print_##CUSTOM_ACCESSOR(NAME); } +#define PARAM_UINT(NAME, DEFAULT_VALUE, CUSTOM_ACCESSOR) { print_##CUSTOM_ACCESSOR(NAME); } +#define PARAM_ULONG(NAME, DEFAULT_VALUE, CUSTOM_ACCESSOR) { print_##CUSTOM_ACCESSOR(NAME); } +#define PARAM_BOOL(NAME, DEFAULT_VALUE, CUSTOM_ACCESSOR) { print_##CUSTOM_ACCESSOR(NAME); } +#define PARAM_DOUBLE(NAME, DEFAULT_VALUE, CUSTOM_ACCESSOR) { print_##CUSTOM_ACCESSOR(NAME); } +#define PARAM_STRING(NAME, DEFAULT_VALUE, CUSTOM_ACCESSOR) { print_##CUSTOM_ACCESSOR(NAME); } +#define PARAM_ARRAY( NAME, TYPE, DEFAULT_ARRAY_SIZE, DEFAULT_VALUE, CUSTOM_ACCESSOR ) { out << #NAME << ": ARRAY" << endl; } +#define PARAM_ARRAY2D( NAME, TYPE, D1_DEFAULT_ARRAY_SIZE, D2_DEFAULT_ARRAY_SIZE, DEFAULT_VALUE, CUSTOM_ACCESSOR ) { out << #NAME << ": ARRAY2D" << endl; } +#define PARAM_ARRAY3D( NAME, TYPE, D1_DEFAULT_ARRAY_SIZE, D2_DEFAULT_ARRAY_SIZE, D3_DEFAULT_ARRAY_SIZE, DEFAULT_VALUE, CUSTOM_ACCESSOR ) { out << #NAME << ": ARRAY3D" << endl; } +#include CONFIG_VAR_FILENAME #undef PARAM #undef PARAM_UINT #undef PARAM_ULONG @@ -172,15 +228,17 @@ static void print_parameters(ostream& out) #undef PARAM_DOUBLE #undef PARAM_STRING #undef PARAM_ARRAY +#undef PARAM_ARRAY2D +#undef PARAM_ARRAY3D } void RubyConfig::printConfiguration(ostream& out) { out << "Ruby Configuration" << endl; out << "------------------" << endl; - out << "protocol: " << CURRENT_PROTOCOL << endl; + //out << "protocol: " << CURRENT_PROTOCOL << endl; out << "compiled_at: " << __TIME__ << ", " << __DATE__ << endl; - out << "RUBY_DEBUG: " << bool_to_string(RUBY_DEBUG) << endl; + // out << "RUBY_DEBUG: " << bool_to_string(RUBY_DEBUG) << endl; char buffer[100]; gethostname(buffer, 50); diff --git a/src/mem/ruby/config/RubyConfig.hh b/src/mem/ruby/config/RubyConfig.hh index 6de6bd1aa..f2e3a0f13 100644 --- a/src/mem/ruby/config/RubyConfig.hh +++ b/src/mem/ruby/config/RubyConfig.hh @@ -40,12 +40,13 @@ #ifndef RUBYCONFIG_H #define RUBYCONFIG_H -#include "mem/ruby/common/Global.hh" -#include "mem/gems_common/ioutil/vardecl.hh" -#include "mem/ruby/system/NodeID.hh" +#include +#include +#include +#include -#define MEMORY_LATENCY RubyConfig::memoryResponseLatency() -#define ABORT_DELAY m_chip_ptr->getTransactionManager(m_version)->getAbortDelay() +#include "mem/ruby/common/TypeDefines.hh" +#define CONFIG_VAR_FILENAME "mem/ruby/config/config.hh" // Set paramterization /* @@ -61,96 +62,169 @@ */ const int NUMBER_WORDS_PER_SET = 4; +using namespace std; + class RubyConfig { public: // CACHE BLOCK CONFIG VARIBLES - static int dataBlockBits() { return g_DATA_BLOCK_BITS; } - static int dataBlockBytes() { return g_DATA_BLOCK_BYTES; } + static uint32 dataBlockMask() { return m_data_block_mask; } + + static int numberOfDMA() { return 1; } + static int numberOfDMAPerChip() { return 1; } + static int DMATransitionsPerCycle() { return 1; } // SUPPORTED PHYSICAL MEMORY CONFIG VARIABLES - static int pageSizeBits() { return g_PAGE_SIZE_BITS; } - static int pageSizeBytes() { return g_PAGE_SIZE_BYTES; } - static int memorySizeBits() { return g_MEMORY_SIZE_BITS; } - static int64 memorySizeBytes() { return g_MEMORY_SIZE_BYTES; } - static int memoryModuleBits() { return g_MEMORY_MODULE_BITS; } - static int64 memoryModuleBlocks() { return g_MEMORY_MODULE_BLOCKS; } - - // returns number of SMT threads per physical processor - static int numberofSMTThreads() { return g_NUM_SMT_THREADS; } + // static int memoryModuleBits() { return m_MEMORY_MODULE_BITS; } + // static int64 memoryModuleBlocks() { return m_MEMORY_MODULE_BLOCKS; } + // defines the number of simics processors (power of 2) - static int numberOfProcessors() { return g_NUM_PROCESSORS; } - static int procsPerChipBits() { return g_PROCS_PER_CHIP_BITS; } - static int numberOfProcsPerChip() { return g_PROCS_PER_CHIP; } - static int numberOfChips() { return g_NUM_CHIPS; } + // static int numberOfProcessors() { return m_NUM_PROCESSORS; } + // static int procsPerChipBits() { return m_PROCS_PER_CHIP_BITS; } + // static int numberOfProcsPerChip() { return m_ProcsPerChip; } + // static int numberOfChips() { return m_NUM_CHIPS; } // MACHINE INSTANIATION CONFIG VARIABLES // ------------------------------------- // L1 CACHE MACHINES // defines the number of L1banks - idependent of ruby chips (power of 2) // NOTE - no protocols currently supports L1s != processors, just a placeholder - static int L1CacheBits() { return g_NUM_PROCESSORS_BITS; } - static int numberOfL1Cache() { return g_NUM_PROCESSORS; } - static int L1CachePerChipBits() { return procsPerChipBits() ; } // L1s != processors not currently supported - static int numberOfL1CachePerChip() { return numberOfProcsPerChip(); } // L1s != processors not currently supported - static int numberOfL1CachePerChip(NodeID myNodeID) { return numberOfL1CachePerChip(); } - static int L1CacheTransitionsPerCycle() { return L1CACHE_TRANSITIONS_PER_RUBY_CYCLE; } - - // L2 CACHE MACHINES - // defines the number of L2banks/L2Caches - idependent of ruby chips (power of 2) - static int L2CacheBits() { return g_NUM_L2_BANKS_BITS; } - static int numberOfL2Cache() { return g_NUM_L2_BANKS; } - static int L1CacheNumToL2Base(NodeID L1RubyNodeID); - static int L2CachePerChipBits() { return g_NUM_L2_BANKS_PER_CHIP_BITS; } - static int numberOfL2CachePerChip() { return g_NUM_L2_BANKS_PER_CHIP; } - static int numberOfL2CachePerChip(NodeID myNodeID) { return numberOfL2CachePerChip(); } - static int L2CacheTransitionsPerCycle() { return L2CACHE_TRANSITIONS_PER_RUBY_CYCLE; } // DIRECTORY/MEMORY MACHINES // defines the number of ruby memories - idependent of ruby chips (power of 2) - static int memoryBits() { return g_NUM_MEMORIES_BITS; } - static int numberOfDirectory() { return numberOfMemories(); } - static int numberOfMemories() { return g_NUM_MEMORIES; } - static int numberOfDirectoryPerChip() { return g_NUM_MEMORIES_PER_CHIP; } - static int numberOfDirectoryPerChip(NodeID myNodeID) { return g_NUM_MEMORIES_PER_CHIP; } - static int DirectoryTransitionsPerCycle() { return DIRECTORY_TRANSITIONS_PER_RUBY_CYCLE; } - - // PERSISTENT ARBITER MACHINES - static int numberOfPersistentArbiter() { return numberOfMemories(); } - static int numberOfPersistentArbiterPerChip() {return numberOfDirectoryPerChip(); } - static int numberOfPersistentArbiterPerChip(NodeID myNodeID) {return numberOfDirectoryPerChip(myNodeID); } - static int PersistentArbiterTransitionsPerCycle() { return L2CACHE_TRANSITIONS_PER_RUBY_CYCLE; } + // static int memoryBits() { return m_NUM_MEMORIES_BITS; } + // static int numberOfDirectory() { return numberOfMemories(); } + // static int numberOfMemories() { return m_NUM_MEMORIES; } + // static int numberOfDirectoryPerChip() { return m_NUM_MEMORIES_PER_CHIP; } + // static int DirectoryTransitionsPerCycle() { return m_DIRECTORY_TRANSITIONS_PER_RUBY_CYCLE; } // ---- END MACHINE SPECIFIC VARIABLES ---- // VARIABLE MEMORY RESPONSE LATENCY // *** NOTE *** This is where variation is added to the simulation // see Alameldeen et al. HPCA 2003 for further details - static int memoryResponseLatency() { return MEMORY_RESPONSE_LATENCY_MINUS_2+(random() % 5); } +// static int getMemoryLatency() { return m_MEMORY_RESPONSE_LATENCY_MINUS_2+(random() % 5); } + static void reset(); static void init(); - static void printConfiguration(ostream& out); + static void printConfiguration(std::ostream& out); // Memory Controller - static int memBusCycleMultiplier () { return MEM_BUS_CYCLE_MULTIPLIER; } - static int banksPerRank () { return BANKS_PER_RANK; } - static int ranksPerDimm () { return RANKS_PER_DIMM; } - static int dimmsPerChannel () { return DIMMS_PER_CHANNEL; } - static int bankBit0 () { return BANK_BIT_0; } - static int rankBit0 () { return RANK_BIT_0; } - static int dimmBit0 () { return DIMM_BIT_0; } - static int bankQueueSize () { return BANK_QUEUE_SIZE; } - static int bankBusyTime () { return BANK_BUSY_TIME; } - static int rankRankDelay () { return RANK_RANK_DELAY; } - static int readWriteDelay () { return READ_WRITE_DELAY; } - static int basicBusBusyTime () { return BASIC_BUS_BUSY_TIME; } - static int memCtlLatency () { return MEM_CTL_LATENCY; } - static int refreshPeriod () { return REFRESH_PERIOD; } - static int tFaw () { return TFAW; } - static int memRandomArbitrate () { return MEM_RANDOM_ARBITRATE; } - static int memFixedDelay () { return MEM_FIXED_DELAY; } + +// static int memBusCycleMultiplier () { return m_MEM_BUS_CYCLE_MULTIPLIER; } +/* static int banksPerRank () { return m_BANKS_PER_RANK; } + static int ranksPerDimm () { return m_RANKS_PER_DIMM; } + static int dimmsPerChannel () { return m_DIMMS_PER_CHANNEL; } + static int bankBit0 () { return m_BANK_BIT_0; } + static int rankBit0 () { return m_RANK_BIT_0; } + static int dimmBit0 () { return m_DIMM_BIT_0; } + static int bankQueueSize () { return m_BANK_QUEUE_SIZE; } + static int bankBusyTime () { return m_BankBusyTime; } + static int rankRankDelay () { return m_RANK_RANK_DELAY; } + static int readWriteDelay () { return m_READ_WRITE_DELAY; } + static int basicBusBusyTime () { return m_BASIC_BUS_BUSY_TIME; } + static int memCtlLatency () { return m_MEM_CTL_LATENCY; } + static int refreshPeriod () { return m_REFRESH_PERIOD; } + static int tFaw () { return m_TFAW; } + static int memRandomArbitrate () { return m_MEM_RANDOM_ARBITRATE; } + static int memFixedDelay () { return m_MEM_FIXED_DELAY; } +*/ + /* cache accessors */ + static int getCacheIDFromParams(int level, int num, string split_type) { + // TODO: this function + return 0; + } + +#define accessor_true( TYPE, NAME ) +#define accessor_false( TYPE, NAME ) \ + static TYPE get##NAME() { return m_##NAME; } \ + static void set##NAME(TYPE val) { m_##NAME = val; } + +#define array_accessor_true( TYPE, NAME, DEFAULT_ARRAY_SIZE ) +#define array_accessor_false( TYPE, NAME, DEFAULT_ARRAY_SIZE ) \ + static TYPE get##NAME(int idx) { \ + assert(m_##NAME != NULL); \ + return m_##NAME[idx]; \ + } \ + static void set##NAME(int idx, TYPE val) { \ + if(m_##NAME == NULL) { \ + assert(DEFAULT_ARRAY_SIZE > 0); \ + m_##NAME = new TYPE[DEFAULT_ARRAY_SIZE]; \ + } \ + m_##NAME[idx] = val; \ + } + +#define array2d_accessor_true( TYPE, NAME ) +#define array2d_accessor_false( TYPE, NAME ) \ + static TYPE get##NAME(int idx1, int idx2) { return m_##NAME[idx1][idx2]; } \ + static void set##NAME(int idx1, int idx2, TYPE val) { m_##NAME[idx1][idx2] = val; } + +#define array3d_accessor_true( TYPE, NAME ) +#define array3d_accessor_false( TYPE, NAME ) \ + static TYPE get##NAME(int idx1, int idx2, int idx3) { return m_##NAME[idx1][idx2][idx3]; } \ + static void set##NAME(int idx1, int idx2, int idx3, TYPE val) { m_##NAME[idx1][idx2][idx3] = val; } + +#define PARAM( NAME, DEFAULT_VALUE, CUSTOM_ACCESSOR ) \ + accessor_##CUSTOM_ACCESSOR(int32,NAME) +#define PARAM_UINT( NAME, DEFAULT_VALUE, CUSTOM_ACCESSOR ) \ + accessor_##CUSTOM_ACCESSOR(uint32,NAME) +#define PARAM_ULONG( NAME, DEFAULT_VALUE, CUSTOM_ACCESSOR ) \ + accessor_##CUSTOM_ACCESSOR(uint64,NAME) +#define PARAM_BOOL( NAME, DEFAULT_VALUE,CUSTOM_ACCESSOR ) \ + accessor_##CUSTOM_ACCESSOR(bool,NAME) +#define PARAM_DOUBLE( NAME, DEFAULT_VALUE, CUSTOM_ACCESSOR ) \ + accessor_##CUSTOM_ACCESSOR(double,NAME) +#define PARAM_STRING( NAME, DEFAULT_VALUE, CUSTOM_ACCESSOR ) \ + accessor_##CUSTOM_ACCESSOR(const char*,NAME) +#define PARAM_ARRAY( NAME, TYPE, DEFAULT_ARRAY_SIZE, DEFAULT_VALUE, CUSTOM_ACCESSOR ) \ + array_accessor_##CUSTOM_ACCESSOR(TYPE, NAME, DEFAULT_ARRAY_SIZE) +#define PARAM_ARRAY2D( NAME, TYPE, D1_DEFAULT_ARRAY_SIZE, D2_DEFAULT_ARRAY_SIZE, DEFAULT_VALUE, CUSTOM_ACCESSOR ) \ + array2d_accessor_##CUSTOM_ACCESSOR(TYPE, NAME) +#define PARAM_ARRAY3D( NAME, TYPE, D1_DEFAULT_ARRAY_SIZE, D2_DEFAULT_ARRAY_SIZE, D3_DEFAULT_ARRAY_SIZE, DEFAULT_VALUE, CUSTOM_ACCESSOR ) \ + array3d_accessor_##CUSTOM_ACCESSOR(TYPE, NAME) +#include CONFIG_VAR_FILENAME +#undef PARAM +#undef PARAM_UINT +#undef PARAM_ULONG +#undef PARAM_BOOL +#undef PARAM_DOUBLE +#undef PARAM_STRING +#undef PARAM_ARRAY +#undef PARAM_ARRAY2D +#undef PARAM_ARRAY3D private: + static uint32 m_data_block_mask; + +#define PARAM( NAME, DEFAULT_VALUE, CUSTOM_ACCESSOR ) \ + static int32 m_##NAME; +#define PARAM_UINT( NAME, DEFAULT_VALUE, CUSTOM_ACCESSOR ) \ + static uint32 m_##NAME; +#define PARAM_ULONG( NAME, DEFAULT_VALUE, CUSTOM_ACCESSOR ) \ + static uint64 m_##NAME; +#define PARAM_BOOL( NAME, DEFAULT_VALUE, CUSTOM_ACCESSOR ) \ + static bool m_##NAME; +#define PARAM_DOUBLE( NAME, DEFAULT_VALUE, CUSTOM_ACCESSOR ) \ + static double m_##NAME; +#define PARAM_STRING( NAME, DEFAULT_VALUE, CUSTOM_ACCESSOR ) \ + static const char *m_##NAME; +#define PARAM_ARRAY( NAME, TYPE, DEFAULT_ARRAY_SIZE, DEFAULT_VALUE, CUSTOM_ACCESSOR ) \ + static TYPE* m_##NAME; +#define PARAM_ARRAY2D( NAME, TYPE, D1_DEFAULT_ARRAY_SIZE, D2_DEFAULT_ARRAY_SIZE, DEFAULT_VALUE, CUSTOM_ACCESSOR ) \ + static TYPE** m_##NAME; +#define PARAM_ARRAY3D( NAME, TYPE, D1_DEFAULT_ARRAY_SIZE, D2_DEFAULT_ARRAY_SIZE, D3_DEFAULT_ARRAY_SIZE, DEFAULT_VALUE, CUSTOM_ACCESSOR ) \ + static TYPE*** m_##NAME; +#include CONFIG_VAR_FILENAME +#undef PARAM +#undef PARAM_UINT +#undef PARAM_ULONG +#undef PARAM_BOOL +#undef PARAM_DOUBLE +#undef PARAM_STRING +#undef PARAM_ARRAY +#undef PARAM_ARRAY2D +#undef PARAM_ARRAY3D + }; #endif //RUBYCONFIG_H diff --git a/src/mem/ruby/config/cfg.rb b/src/mem/ruby/config/cfg.rb new file mode 100644 index 000000000..de8bcafd2 --- /dev/null +++ b/src/mem/ruby/config/cfg.rb @@ -0,0 +1,751 @@ +#!/usr/bin/ruby + +class AssertionFailure < RuntimeError +end + +class Boolean + def self.is_a?(obj) + return self.name == "Boolean" + end +end + +def assert(condition,message) + unless condition + raise AssertionFailure, "Assertion failed: #{message}" + end +end + +class LibRubyObject + @@all_objs = Array.new + attr_reader :obj_name + @@default_params = Hash.new + + def initialize(obj_name) + assert obj_name.is_a?(String), "Obj_Name must be a string" + @obj_name = obj_name + @@all_objs << self + @params = Hash.new + end + + def cppClassName() + raise NotImplementedException + end + + def self.param(param_name, type) + idx = self.name.to_sym + @@default_params[idx] = Hash.new if ! @@default_params.key?(idx) + @@default_params[idx][param_name] = nil + send :define_method, param_name do + @params[param_name] = @@default_params[idx][param_name] if ! @params.key?(param_name) + @params[param_name] + end + method_name = (param_name.to_s + "=").to_sym + send :define_method, method_name do |val| + if val.is_a?(FalseClass) || val.is_a?(TrueClass) + assert type.is_a?(Boolean), "default value of param \"#{param_name}\" must be either true or false" + else + assert val.is_a?(type), "default value of param \"#{param_name}\" does not match type #{type}" + end +# assert val.is_a?(type), "#{param_name} must be of type #{type}" + @params[param_name] = val + end + end + + def self.default_param(param_name, type, default) + idx = self.name.to_sym + @@default_params[idx] = Hash.new if ! @@default_params.key?(idx) + if default.is_a?(FalseClass) || default.is_a?(TrueClass) + assert type.is_a?(Boolean), "default value of param \"#{param_name}\" must be either true or false" + else + assert default.is_a?(type), "default value of param \"#{param_name}\" does not match type #{type}" + end + @@default_params[idx][param_name] = default + send :define_method, param_name do + @params[param_name] = @@default_params[idx][param_name] if ! @params.key?(param_name) + @params[param_name] + end + method_name = (param_name.to_s + "=").to_sym + send :define_method, method_name do |val| + assert val.is_a?(type), "#{param_name} must be of type #{type}" + @params[param_name] = val + end + end + + def applyDefaults() + idx = self.class.name.to_sym + @@default_params[idx] = Hash.new if ! @@default_params.key?(idx) + @@default_params[idx].each { |key, val| + @params[key] = val if ! @params.key?(key) + } + end + + def argv() + str = "" + + applyDefaults + + @params.each { |key, val| + str += key.id2name + " " + if val.is_a?(LibRubyObject) + str += val.obj_name + " " + else + if val.is_a?(String) and val == "" + str += "null " + else + str += val.to_s + " " + end + end + } + return str + end + + def self.printConstructors() + @@all_objs.each { |obj| + print obj.cppClassName, " ", obj.obj_name, " ",obj.argv,"\n" + } + end + def self.all() + @@all_objs + end +end + +class IfacePort < LibRubyObject + def initialize(obj_name) + super(obj_name) + end + + def bochsConnType + raise NotImplementedException + end +end + +class NetPort < LibRubyObject + attr :mach_type + attr_reader :version + + @@type_cnt = Hash.new + @type_id + def initialize(obj_name, mach_type) + super(obj_name) + @mach_type = mach_type + @@type_cnt[mach_type] ||= 0 + @type_id = @@type_cnt[mach_type] + @@type_cnt[mach_type] += 1 + + idx = "NetPort".to_sym + @@default_params[idx] = Hash.new if ! @@default_params.key?(idx) + @@default_params[idx].each { |key, val| + @params[key] = val if ! @params.key?(key) + } + end + + def port_name + mach_type + end + def port_num + @type_id + end + def cppClassName + "NetPort" + end +end + +class MemoryVector < LibRubyObject + def initialize(obj_name) + super(obj_name) + end + + def cppClassName + "MemoryController" + end +end + +class Debug < LibRubyObject + def initialize *args + case args.size + when 1 + super(args[0]) + when 6 + init_params *args[1] + else + raise Exception + end + end + + def init_params (protocol_trace, filter_string, verbosity_string, start_time, output_filename) + @params[:protocol_trace] = protocol_trace + @params[:filter_string] = filter_string + @params[:verbosity_string] = verbosity_string + @params[:start_time] = start_time + @params[:output_filename] = output_filename + end + + def cppClassName + "Debug" + end +end + +class RubySystem + + @@params = Hash.new + @@network = nil + + def self.init(iface_ports, network) + @@iface_ports = iface_ports + @@network = network + end + + def self.default_param(param_name, type, default) + if default.is_a?(FalseClass) || default.is_a?(TrueClass) + assert type.is_a?(Boolean), "default value of param \"#{param_name}\" must be either true or false" + else + assert default.is_a?(type), "default value of param \"#{param_name}\" does not match type #{type}" + end + @@params[param_name] = default + method_name = (param_name.to_s).to_sym + instance_eval <<-EOS + def #{method_name.to_s} + @@params[:#{param_name.to_s}] + end + EOS + instance_eval <<-EOS + def #{method_name.to_s}=(val) + @@params[:#{param_name.to_s}] = val + end + EOS + end + + def self.generateConfig() + # get current time for random seed if set to "rand" + if @@params[:random_seed] == "rand" + t = Time.now + @@params[:random_seed] = t.usec.to_i + end + if ! @@params[:random_seed].is_a?(Integer) + raise TypeException + end + print "System sys0 ",argv,"\n" + LibRubyObject.all.each { |obj| + if obj.is_a?(SetAssociativeCache) + obj.calculateLatency + end + } + LibRubyObject.printConstructors + end + + def self.printIfacePorts() + @@iface_ports.each { |port| + print port.obj_name, " " + } + puts + end + + def self.getBochsConnections() + ports = Hash.new + @@iface_ports.each { |port| + ports[port.obj_name] = port.bochsConnType + } + return ports + end + + def self.getMemorySizeMB() + DirectoryMemory.memorySizeMB + end + + # override the default accessors (generated by default_param) for random_seed + def self.random_seed=(seed) + assert (val.is_a?(Integer) or val == "rand"), "RubySystem.random_seed takes either an integer value or the string \"rand\"" + @@params[:random_seed] = seed + end + +private + + def self.argv() + str = "" + @@params.each { |key, val| + str += key.id2name + " " + str += val.to_s + " " + } + return str + end + + def self.writeConfig() + @@network.printTopology + end + +end + +#require "defaults.rb" + + + +class CacheController < NetPort + @@total_cache_controllers = 0 + attr :caches + attr :sequencer + def initialize(obj_name, mach_type, caches, sequencer) + super(obj_name, mach_type) + @caches = caches + @caches.each { |cache| + cache.controller = self + } + + @sequencer = sequencer + @sequencer.controller = self + + @version = @@total_cache_controllers + @@total_cache_controllers += 1 + @sequencer.version = @version + buffer_size() + end + + def argv() + vec = "version "+@version.to_s + @caches.each { |cache| + vec += " cache " + cache.obj_name + } + vec += " sequencer "+@sequencer.obj_name + vec += " transitions_per_cycle "+@params[:transitions_per_cycle].to_s + vec += " buffer_size "+@params[:buffer_size].to_s + vec += " number_of_TBEs "+@params[:number_of_TBEs].to_s + + end + + def cppClassName() + "generated:"+@mach_type + end +end + +class DirectoryController < NetPort + @@total_directory_controllers = 0 + attr :directory + attr :memory_control + + def initialize(obj_name, mach_type, directory, memory_control) + super(obj_name, mach_type) + + @directory = directory + directory.controller = self + + @memory_control = memory_control + + @version = @@total_directory_controllers + @@total_directory_controllers += 1 + buffer_size() + end + + def argv() + "version "+@version.to_s+" directory_name "+@directory.obj_name+" transitions_per_cycle "+@params[:transitions_per_cycle].to_s + " buffer_size "+@params[:buffer_size].to_s + " number_of_TBEs "+@params[:number_of_TBEs].to_s + " memory_controller_name "+@memory_control.obj_name + " recycle_latency "+@params[:recycle_latency].to_s + end + + def cppClassName() + "generated:"+@mach_type + end + +end + +class DMAController < NetPort + @@total_dma_controllers = 0 + attr :dma_sequencer + def initialize(obj_name, mach_type, dma_sequencer) + super(obj_name, mach_type) + @dma_sequencer = dma_sequencer + @version = @@total_dma_controllers + @@total_dma_controllers += 1 + dma_sequencer.controller = self + buffer_size + end + + def argv() + "version "+@version.to_s+" dma_sequencer "+@dma_sequencer.obj_name+" transitions_per_cycle "+@params[:transitions_per_cycle].to_s + " buffer_size "+@params[:buffer_size].to_s + " number_of_TBEs "+@params[:number_of_TBEs].to_s + end + + def cppClassName() + "generated:"+@mach_type + end +end + +class Cache < LibRubyObject + attr :size_kb, :latency + attr_writer :controller + def initialize(obj_name, size_kb, latency) + super(obj_name) + assert size_kb.is_a?(Integer), "Cache size must be an integer" + @size_kb = size_kb + @latency = latency + end + + def args + "controller "+@controller.obj_name+" size_kb "+@size_kb.to_s+" latency "+@latency.to_s + end +end + +class SetAssociativeCache < Cache + attr :assoc, :replacement_policy + + # latency can be either an integer, a float, or the string "auto" + # when an integer, it represents the number of cycles for a hit + # when a float, it represents the cache access time in ns + # when set to "auto", libruby will attempt to find a realistic latency by running CACTI + def initialize(obj_name, size_kb, latency, assoc, replacement_policy) + super(obj_name, size_kb, latency) + @assoc = assoc + @replacement_policy = replacement_policy + end + + def calculateLatency() + if @latency == "auto" + cacti_args = Array.new() + cacti_args << (@size_kb*1024) << RubySystem.block_size_bytes << @assoc + cacti_args << 1 << 0 << 0 << 0 << 1 + cacti_args << RubySystem.tech_nm << RubySystem.block_size_bytes*8 + cacti_args << 0 << 0 << 0 << 1 << 0 << 0 << 0 << 0 << 1 + cacti_args << 360 << 0 << 0 << 0 << 0 << 1 << 1 << 1 << 1 << 0 << 0 + cacti_args << 50 << 10 << 10 << 0 << 1 << 1 + + cacti_cmd = File.dirname(__FILE__) + "/cacti/cacti " + cacti_args.join(" ") + + IO.popen(cacti_cmd) { |pipe| + str1 = pipe.readline + str2 = pipe.readline + results = str2.split(", ") + if results.size != 61 + print "CACTI ERROR: CACTI produced unexpected output.\n" + print "Are you using the version shipped with libruby?\n" + raise Exception + end + latency_ns = results[5].to_f + if (latency_ns == "1e+39") + print "CACTI ERROR: CACTI was unable to realistically model the cache ",@obj_name,"\n" + print "Either change the cache parameters or manually set the latency values\n" + raise Exception + end + clk_period_ns = 1e9 * (1.0 / (RubySystem.freq_mhz * 1e6)) + latency_cycles = (latency_ns / clk_period_ns).ceil + @latency = latency_cycles + } + elsif @latency.is_a?(Float) + clk_period_ns = 1e9 * (1.0 / (RubySystem.freq_mhz * 1e6)) + latency_cycles = (@latency / clk_period_ns).ceil + @latency = latency_cycles + elsif ! @latency.is_a?(Integer) + raise Exception + end + end + + def argv() + args+" assoc "+@assoc.to_s+" replacement_policy "+@replacement_policy + end + + def cppClassName() + "SetAssociativeCache" + end +end + +class DirectoryMemory < LibRubyObject + attr :size_mb + attr_writer :controller + @@total_size_mb = 0 + + def initialize(obj_name, size_mb) + super(obj_name) + @size_mb = size_mb + @@total_size_mb += size_mb + end + + def argv() + "version "+@controller.version.to_s+" size_mb "+@size_mb.to_s+" controller "+@controller.obj_name + end + + def cppClassName() + "DirectoryMemory" + end + + def self.memorySizeMB() + @@total_size_mb + end +end + +#added by SS +class MemoryControl < LibRubyObject + attr :name + def initialize(obj_name) + super(obj_name) + @name = obj_name + end + + def argv() + vec = super() + vec += " mem_bus_cycle_multiplier "+mem_bus_cycle_multiplier.to_s + vec += " banks_per_rank "+banks_per_rank.to_s + vec += " ranks_per_dimm "+ranks_per_dimm.to_s + vec += " dimms_per_channel "+dimms_per_channel.to_s + vec += " bank_bit_0 "+bank_bit_0.to_s + vec += " rank_bit_0 "+rank_bit_0.to_s + vec += " dimm_bit_0 "+dimm_bit_0.to_s + vec += " bank_queue_size "+bank_queue_size.to_s + vec += " bank_busy_time "+bank_busy_time.to_s + vec += " rank_rank_delay "+rank_rank_delay.to_s + vec += " read_write_delay "+read_write_delay.to_s + vec += " basic_bus_busy_time "+basic_bus_busy_time.to_s + vec += " mem_ctl_latency "+mem_ctl_latency.to_s + vec += " refresh_period "+refresh_period.to_s + vec += " tFaw "+tFaw.to_s + vec += " mem_random_arbitrate "+mem_random_arbitrate.to_s + vec += " mem_fixed_delay "+mem_fixed_delay.to_s + vec += " memory_controller_name "+@name + + end + + + def cppClassName() + "MemoryControl" + end +end + + + +class Sequencer < IfacePort + + def cppClassName() + "Sequencer" + end + + param :controller, NetPort # must be set after initialization + param :icache, Cache + param :dcache, Cache + param :version, Integer + + def initialize(obj_name, icache, dcache) + super(obj_name) + self.icache=icache + self.dcache=dcache + end + + def bochsConnType() + return "cpu"+version.to_s + end + +end + + + +class DMASequencer < IfacePort + def initialize(obj_name) + super(obj_name) + @params = { + :controller => nil, + :version => nil + } + end + + def controller=(controller) + @params[:controller] = controller.obj_name + @params[:version] = controller.version + end + + def cppClassName() + "DMASequencer" + end + + def bochsConnType() + return "dma"+@params[:version].to_s + end +end + +class IntNode + @@num = 0 + def initialize() + + end +end + +class Network < LibRubyObject +end + +class Topology < LibRubyObject + attr :net_ports + param :network, Network + def initialize(name, net_ports) + super(name) + @net_ports = net_ports + end + + def cppClassName + "Topology" + end +end + +class Network < LibRubyObject + param :topology, Topology + def initialize(name, topo) + super(name) + @params[:topology] = topo + topo.network= self + end + + def argv() + vec = super() + + vec += " endpoint_bandwidth "+endpoint_bandwidth.to_s + vec += " adaptive_routing "+adaptive_routing.to_s + vec += " number_of_virtual_networks "+number_of_virtual_networks.to_s + vec += " fan_out_degree "+fan_out_degree.to_s + + vec += " buffer_size "+buffer_size.to_s + vec += " link_latency "+adaptive_routing.to_s + vec += " on_chip_latency "+on_chip_latency.to_s + + end + + def printTopology() + topology.printFile + end + def cppClassName() + "SimpleNetwork" + end + +end + +class PtToPtTopology < Topology + + param :connections,String + + def initialize(name, net_ports) + super(name, net_ports) + @params[:connections] = "" + @net_ports.each_index { |idx| + @params[:connections] << ("ext_node:"+@net_ports[idx].port_name+":"+@net_ports[idx].port_num.to_s) + @params[:connections] << ("%int_node:"+ idx.to_s+ "%link_latency:"+ link_latency.to_s) + @params[:connections] << ("%bw_multiplier:"+external_bw.to_s+"#") + } + @net_ports.each_index { |outer_idx| + @net_ports.each_index { |inner_idx| + if (outer_idx != inner_idx) + @params[:connections] << ("int_node:"+ outer_idx.to_s+ "%int_node:"+ inner_idx.to_s) + @params[:connections] << ("%link_latency:"+link_latency.to_s+"%bw_multiplier:"+internal_bw.to_s) + @params[:connections] << ("%link_weight:"+1.to_s+"#") + end + } + } + # call the accessors of the parent class to initialize them + # need to find a better method!! + print_config + end + +end + +class CrossbarTopology < Topology + param :connections,String + + def initialize(name, net_ports) + super(name, net_ports) + @params[:connections] = "" + crossbar_node = @net_ports.size + @net_ports.each_index { |idx| + @params[:connections] << ("ext_node:"+@net_ports[idx].port_name+":"+@net_ports[idx].port_num.to_s) + @params[:connections] << ("%int_node:"+ idx.to_s+ "%link_latency:"+ link_latency.to_s) + @params[:connections] << ("%bw_multiplier:"+external_bw.to_s+"#") + } + @net_ports.each_index { |idx| + @params[:connections] << ("int_node:"+idx.to_s+"%int_node:"+crossbar_node.to_s) + @params[:connections] << ("%link_latency:"+link_latency.to_s+"%bw_multiplier:"+internal_bw.to_s) + @params[:connections] << ("%link_weight:"+1.to_s+"#") + } + print_config + end +end + +#added by SS +class Tracer < LibRubyObject + def initialize(obj_name) + super(obj_name) + end + + def cppClassName() + "Tracer" + end + +end + +class Profiler < LibRubyObject + def initialize(obj_name) + super(obj_name) + end + + def cppClassName() + "Profiler" + end + +end + +class MI_example_CacheController < CacheController + def initialize(obj_name, mach_type, caches, sequencer) + super(obj_name, mach_type, caches, sequencer) + end + def argv() + vec = super() + vec += " issue_latency "+issue_latency.to_s + vec += " cache_response_latency "+cache_response_latency.to_s + end + +end + +class MI_example_DirectoryController < DirectoryController + def initialize(obj_name, mach_type, directory, memory_control) + super(obj_name, mach_type, directory, memory_control) + end + def argv() + vec = super() + vec += " to_mem_ctrl_latency "+to_mem_ctrl_latency.to_s + vec += " directory_latency "+directory_latency.to_s + vec += " memory_latency "+memory_latency.to_s + end + +end + +#added by SS +class GarnetNetwork < Network + def initialize(name, topo) + super(name, topo) + end + def argv() + vec = super() + vec += " flit_size "+flit_size.to_s + vec += " number_of_pipe_stages "+number_of_pipe_stages.to_s + vec += " vcs_per_class "+vcs_per_class.to_s + vec += " buffer_size "+buffer_size.to_s + vec += " using_network_testing "+using_network_testing.to_s + end + +end + +class GarnetFixedPipeline < GarnetNetwork + def initialize(name, net_ports) + super(name, net_ports) + end + + def argv() + super() + end + + def cppClassName() + "GarnetNetwork_d" + end +end + +class GarnetFlexiblePipeline < GarnetNetwork + def initialize(name, net_ports) + super(name, net_ports) + end + + def argv() + super() + end + + def cppClassName() + "GarnetNetwork" + end +end + +require "defaults.rb" diff --git a/src/mem/ruby/config/config.hh b/src/mem/ruby/config/config.hh index 3cad258a2..ad91cd73d 100644 --- a/src/mem/ruby/config/config.hh +++ b/src/mem/ruby/config/config.hh @@ -1,74 +1,23 @@ -// -// This file has been modified by Kevin Moore and Dan Nussbaum of the -// Scalable Systems Research Group at Sun Microsystems Laboratories -// (http://research.sun.com/scalable/) to support the Adaptive -// Transactional Memory Test Platform (ATMTP). For information about -// ATMTP, see the GEMS website: http://www.cs.wisc.edu/gems/. -// -// Please send email to atmtp-interest@sun.com with feedback, questions, or -// to request future announcements about ATMTP. -// -// ---------------------------------------------------------------------- -// -// File modification date: 2008-02-23 -// -// ---------------------------------------------------------------------- -// -// ATMTP is distributed as part of the GEMS software toolset and is -// available for use and modification under the terms of version 2 of the -// GNU General Public License. The GNU General Public License is contained -// in the file $GEMS/LICENSE. -// -// Multifacet GEMS is free software; you can redistribute it and/or modify -// it under the terms of version 2 of the GNU General Public License as -// published by the Free Software Foundation. -// -// Multifacet GEMS is distributed in the hope that it will be useful, but -// WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// General Public License for more details. -// -// You should have received a copy of the GNU General Public License along -// with the Multifacet GEMS; if not, write to the Free Software Foundation, -// Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA -// -// ---------------------------------------------------------------------- -// - -// see rubyconfig.defaults for some explanations - -PARAM( g_RANDOM_SEED ); - -// Maximum number of cycles a request is can be outstanding before the -// Sequencer of StoreBuffer declares we're in deadlock/livelock -PARAM( g_DEADLOCK_THRESHOLD ); -PARAM_BOOL( RANDOMIZATION ); -PARAM_BOOL( g_SYNTHETIC_DRIVER ); -PARAM_BOOL( g_DETERMINISTIC_DRIVER ); // FOR MOESI_CMP_token -PARAM_BOOL( g_FILTERING_ENABLED ); -PARAM_BOOL( g_DISTRIBUTED_PERSISTENT_ENABLED ); -PARAM_BOOL( g_DYNAMIC_TIMEOUT_ENABLED ); -PARAM( g_RETRY_THRESHOLD ); -PARAM( g_FIXED_TIMEOUT_LATENCY ); - -PARAM( g_trace_warmup_length ); -PARAM_DOUBLE( g_bash_bandwidth_adaptive_threshold ); +//PARAM_BOOL( FilteringEnabled, false, false ); +//PARAM_BOOL( DistributedPersistentEnabled, true, false ); +//PARAM_BOOL( DynamicTimeoutEnabled, true, false ); +//PARAM( RetryThreshold, 1, false ); +//PARAM( FixedTimeoutLatency, 300, false ); -PARAM( g_tester_length ); -PARAM( g_synthetic_locks ); -PARAM( g_deterministic_addrs ); -// Specified Generator: See SpecifiedGeneratorType in external.sm for valid values -PARAM_STRING( g_SpecifiedGenerator ); -PARAM( g_callback_counter ); -PARAM( g_NUM_COMPLETIONS_BEFORE_PASS ); +//PARAM( TraceWarmupLength, 1000000, false ); -PARAM( g_NUM_SMT_THREADS ); +//PARAM( callback_counter, 0, false ); +//PARAM( NUM_COMPLETIONS_BEFORE_PASS, 0, false ); -PARAM( g_think_time ); -PARAM( g_hold_time ); -PARAM( g_wait_time ); +//PARAM( tester_length, 0, false ); +//PARAM( synthetic_locks, 2048, false ); +//PARAM( think_time, 5, false ); +//PARAM( wait_time, 5, false ); +//PARAM( hold_time, 5, false ); +//PARAM( deterministic_addrs, 1, false ); +//PARAM_STRING( SpecifiedGenerator, "DetermInvGenerator", false ); // For debugging purposes, one can enable a trace of all the protocol // state machine changes. Unfortunately, the code to generate the @@ -80,243 +29,208 @@ PARAM( g_wait_time ); // "g_debug_ptr->setDebugTime(1)" to beging the following to set the // debug begin time // -// this use to be ruby/common/Global.h +// this use to be ruby/common/Global.hh -PARAM_BOOL( PROTOCOL_DEBUG_TRACE ); -// a string for filtering debugging output (for all g_debug vars see Debug.h) -PARAM_STRING( DEBUG_FILTER_STRING ); +//PARAM_BOOL( ProtocolDebugTrace, true, false ); +// a string for filtering debugging output (for all g_debug vars see Debug.hh) +//PARAM_STRING( DEBUG_FILTER_STRING, "", false ); // filters debugging messages based on priority (low, med, high) -PARAM_STRING( DEBUG_VERBOSITY_STRING ); +//PARAM_STRING( DEBUG_VERBOSITY_STRING, "", false ); // filters debugging messages based on a ruby time -PARAM_ULONG( DEBUG_START_TIME ); +//PARAM_ULONG( DEBUG_START_TIME, 0, false ); // sends debugging messages to a output filename -PARAM_STRING( DEBUG_OUTPUT_FILENAME ); - -// defines relative (integer) clock multipliers between ruby, opal, and simics -PARAM( SIMICS_RUBY_MULTIPLIER ); -PARAM( OPAL_RUBY_MULTIPLIER ); +//PARAM_STRING( DEBUG_OUTPUT_FILENAME, "", false ); -PARAM_BOOL( TRANSACTION_TRACE_ENABLED ); -PARAM_BOOL( USER_MODE_DATA_ONLY ); -PARAM_BOOL( PROFILE_HOT_LINES ); +//PARAM_BOOL( ProfileHotLines, false, false ); // PROFILE_ALL_INSTRUCTIONS is used if you want Ruby to profile all instructions executed // The following need to be true for this to work correctly: // 1. Disable istc and dstc for this simulation run // 2. Add the following line to the object "sim" in the checkpoint you run from: -// instruction_profile_line_size: 4 +// instruction_profile_line_size: 4 // This is used to have simics report back all instruction requests // For more details on how to find out how to interpret the output physical instruction // address, please read the document in the simics-howto directory -PARAM_BOOL( PROFILE_ALL_INSTRUCTIONS ); +//PARAM_BOOL( ProfileAllInstructions, false, false ); // Set the following variable to true if you want a complete trace of // PCs (physical address of program counters, with executing processor IDs) // to be printed to stdout. Make sure to direct the simics output to a file. // Otherwise, the run will take a really long time! // A long run may write a file that can exceed the OS limit on file length -PARAM_BOOL( PRINT_INSTRUCTION_TRACE ); -PARAM( g_DEBUG_CYCLE ); - -// Don't allow any datablocks to enter the STC -PARAM_BOOL( BLOCK_STC ); +//PARAM_BOOL( PRINT_INSTRUCTION_TRACE, false, false ); +//PARAM( DEBUG_CYCLE, 0, false ); // Make the entire memory system perfect -PARAM_BOOL( PERFECT_MEMORY_SYSTEM ); -PARAM( PERFECT_MEMORY_SYSTEM_LATENCY ); - -PARAM_BOOL( DATA_BLOCK ); // Define NO_DATA_BLOCK to make the DataBlock take zero space - -PARAM_BOOL( REMOVE_SINGLE_CYCLE_DCACHE_FAST_PATH ); +//PARAM_BOOL( PERFECT_MEMORY_SYSTEM, false, false ); +//PARAM( PERFECT_MEMORY_SYSTEM_LATENCY, 0, false ); // ********************************************* -// CACHE & MEMORY PARAMETERS +// SYSTEM PARAMETERS // ********************************************* +//PARAM( NumberOfChips, 1, false ); +//PARAM( NumberOfCores, 2, false ); +//PARAM_ARRAY( NumberOfCoresPerChip, int, m_NumberOfChips, 2, false); -PARAM( L1_CACHE_ASSOC ); -PARAM( L1_CACHE_NUM_SETS_BITS ); -PARAM( L2_CACHE_ASSOC ); -PARAM( L2_CACHE_NUM_SETS_BITS ); - -PARAM_ULONG( g_MEMORY_SIZE_BYTES ); -PARAM( g_DATA_BLOCK_BYTES ); -// The following page size parameter is used by the stride prefetcher -PARAM( g_PAGE_SIZE_BYTES ); -PARAM_STRING( g_REPLACEMENT_POLICY ); +// ********************************************* +// CACHE PARAMETERS +// ********************************************* -PARAM( g_NUM_PROCESSORS ); -PARAM( g_NUM_L2_BANKS ); -PARAM( g_NUM_MEMORIES ); -PARAM( g_PROCS_PER_CHIP ); +//PARAM( NumberOfCaches, m_NumberOfCores, false ); +//PARAM( NumberOfCacheLevels, 1, false ); +/* this returns the number of discrete CacheMemories per level (i.e. a split L1 counts for 2) */ +//PARAM_ARRAY( NumberOfCachesPerLevel, int, m_NumberOfCacheLevels, m_NumberOfCores, false ); // this is the number of discrete caches if the level is private + // or the number of banks if the level is shared +//PARAM( CacheIDFromParams, 1, true ); // returns a unique CacheID from the parameters (level, num, split_type) +//PARAM_ARRAY( CacheLatency, int, m_NumberOfCaches, 1, false ); // returns the latency for cache, indexed by CacheID +//PARAM_ARRAY( CacheSplitType, string, m_NumberOfCaches, "unified", false ); // returns "data", "instruction", or "unified", indexed by CacheID +//PARAM_ARRAY( CacheType, string, m_NumberOfCaches, "SetAssociative", false ); // returns the type of a cache, indexed by CacheID +//PARAM_ARRAY( CacheAssoc, int, m_NumberOfCaches, 4, false ); // returns the cache associativity, indexed by CacheID +//PARAM_ARRAY( NumberOfCacheSets, int, m_NumberOfCaches, 256, false ); // returns the number of cache sets, indexed by CacheID +//PARAM_ARRAY( NumberOfCacheSetBits, int, m_NumberOfCaches, log_int(256), false ); // returns the number of cache set bits, indexed by CacheID +//PARAM_ARRAY( CacheReplacementPolicy, string, m_NumberOfCaches, "PSEUDO_LRU", false ); // other option is "LRU" + +//PARAM( DataBlockBytes, 64, false ); +//PARAM( DataBlockBits, log_int(m_DataBlockBytes), false); + +// ******************************************** +// MEMORY PARAMETERS +// ******************************************** + +//PARAM_ARRAY( NumberOfControllersPerType, int, m_NumberOfCacheLevels+2, m_NumberOfCores, false); +//PARAM_ARRAY2D( NumberOfControllersPerTypePerChip, int, m_NumberOfCacheLevels+2, m_NumberOfChips, m_NumberOfCores, false); + +// ******************************************** +// DMA CONTROLLER PARAMETERS +// ******************************************** + +//PARAM( NumberOfDMA, 1, false ); +//PARAM_ARRAY( NumberOfDMAPerChip, int, m_NumberOfChips, 1, false); +//PARAM_ARRAY( ChipNumFromDMAVersion, int, m_NumberOfDMA, 0, false ); + +//PARAM_ULONG( MemorySizeBytes, 4294967296, false ); +//PARAM_ULONG( MemorySizeBits, 32, false); + +//PARAM( NUM_PROCESSORS, 0, false ); +//PARAM( NUM_L2_BANKS, 0, false ); +//PARAM( NUM_MEMORIES, 0, false ); +//PARAM( ProcsPerChip, 1, false ); // The following group of parameters are calculated. They must // _always_ be left at zero. -PARAM( g_NUM_CHIPS ); -PARAM( g_NUM_CHIP_BITS ); -PARAM( g_MEMORY_SIZE_BITS ); -PARAM( g_DATA_BLOCK_BITS ); -PARAM( g_PAGE_SIZE_BITS ); -PARAM( g_NUM_PROCESSORS_BITS ); -PARAM( g_PROCS_PER_CHIP_BITS ); -PARAM( g_NUM_L2_BANKS_BITS ); -PARAM( g_NUM_L2_BANKS_PER_CHIP_BITS ); -PARAM( g_NUM_L2_BANKS_PER_CHIP ); -PARAM( g_NUM_MEMORIES_BITS ); -PARAM( g_NUM_MEMORIES_PER_CHIP ); -PARAM( g_MEMORY_MODULE_BITS ); -PARAM_ULONG( g_MEMORY_MODULE_BLOCKS ); - -// determines the mapping between L2 banks and sets within L2 banks -PARAM_BOOL( MAP_L2BANKS_TO_LOWEST_BITS ); +//PARAM( NUM_CHIPS, 0, false ); +//PARAM( NUM_CHIP_BITS, 0, false ); +//PARAM( MEMORY_SIZE_BITS, 0, false ); +//PARAM( DATA_BLOCK_BITS, 0, false ); +//PARAM( PAGE_SIZE_BITS, 0, false ); +//PARAM( NUM_PROCESSORS_BITS, 0, false ); +//PARAM( PROCS_PER_CHIP_BITS, 0, false ); +//PARAM( NUM_L2_BANKS_BITS, 0, false ); +//PARAM( NUM_L2_BANKS_PER_CHIP_BITS, 0, false ); +//PARAM( NUM_L2_BANKS_PER_CHIP, 0, false ); +//PARAM( NUM_MEMORIES_BITS, 0, false ); +//PARAM( NUM_MEMORIES_PER_CHIP, 0, false ); +//PARAM( MEMORY_MODULE_BITS, 0, false ); +//PARAM_ULONG( MEMORY_MODULE_BLOCKS, 0, false ); // TIMING PARAMETERS -PARAM( DIRECTORY_CACHE_LATENCY ); - -PARAM( NULL_LATENCY ); -PARAM( ISSUE_LATENCY ); -PARAM( CACHE_RESPONSE_LATENCY ); -PARAM( L2_RESPONSE_LATENCY ); -PARAM( L2_TAG_LATENCY ); -PARAM( L1_RESPONSE_LATENCY ); -PARAM( MEMORY_RESPONSE_LATENCY_MINUS_2 ); -PARAM( DIRECTORY_LATENCY ); -PARAM( NETWORK_LINK_LATENCY ); -PARAM( COPY_HEAD_LATENCY ); -PARAM( ON_CHIP_LINK_LATENCY ); -PARAM( RECYCLE_LATENCY ); -PARAM( L2_RECYCLE_LATENCY ); -PARAM( TIMER_LATENCY ); -PARAM( TBE_RESPONSE_LATENCY ); -PARAM_BOOL( PERIODIC_TIMER_WAKEUPS ); - -// constants used by TM protocols -PARAM_BOOL( PROFILE_EXCEPTIONS ); -PARAM_BOOL( PROFILE_XACT ); -PARAM_BOOL( PROFILE_NONXACT ); -PARAM_BOOL( XACT_DEBUG ); -PARAM ( XACT_DEBUG_LEVEL ); -PARAM_BOOL( XACT_MEMORY ); -PARAM_BOOL( XACT_ENABLE_TOURMALINE ); -PARAM( XACT_NUM_CURRENT ); -PARAM( XACT_LAST_UPDATE ); -PARAM_BOOL( XACT_ISOLATION_CHECK ); -PARAM_BOOL( PERFECT_FILTER ); -PARAM_STRING( READ_WRITE_FILTER ); -PARAM_BOOL( PERFECT_VIRTUAL_FILTER ); -PARAM_STRING( VIRTUAL_READ_WRITE_FILTER ); -PARAM_BOOL( PERFECT_SUMMARY_FILTER ); -PARAM_STRING( SUMMARY_READ_WRITE_FILTER ); -PARAM_BOOL( XACT_EAGER_CD ); -PARAM_BOOL( XACT_LAZY_VM ); -PARAM_STRING( XACT_CONFLICT_RES ); -PARAM_BOOL( XACT_VISUALIZER ); -PARAM( XACT_COMMIT_TOKEN_LATENCY ) ; -PARAM_BOOL( XACT_NO_BACKOFF ); -PARAM ( XACT_LOG_BUFFER_SIZE ); -PARAM ( XACT_STORE_PREDICTOR_HISTORY); -PARAM ( XACT_STORE_PREDICTOR_ENTRIES); -PARAM ( XACT_STORE_PREDICTOR_THRESHOLD); -PARAM ( XACT_FIRST_ACCESS_COST ); -PARAM ( XACT_FIRST_PAGE_ACCESS_COST ); -PARAM_BOOL( ENABLE_MAGIC_WAITING ); -PARAM_BOOL( ENABLE_WATCHPOINT ); -PARAM_BOOL( XACT_ENABLE_VIRTUALIZATION_LOGTM_SE ); - -// ATMTP -PARAM_BOOL( ATMTP_ENABLED ); -PARAM_BOOL( ATMTP_ABORT_ON_NON_XACT_INST ); -PARAM_BOOL( ATMTP_ALLOW_SAVE_RESTORE_IN_XACT ); -PARAM( ATMTP_XACT_MAX_STORES ); -PARAM( ATMTP_DEBUG_LEVEL ); +//PARAM( DIRECTORY_CACHE_LATENCY, 6, false ); + +//PARAM( NULL_LATENCY, 1, false ); +//PARAM( ISSUE_LATENCY, 2, false ); +//PARAM( CACHE_RESPONSE_LATENCY, 12, false ); +//PARAM( L2_RESPONSE_LATENCY, 6, false ); +//PARAM( L2_TAG_LATENCY, 6, false ); +//PARAM( L1_RESPONSE_LATENCY, 3, false ); + +//PARAM( MEMORY_RESPONSE_LATENCY_MINUS_2, 158, false ); +//PARAM( DirectoryLatency, 6, false ); + +//PARAM( NetworkLinkLatency, 1, false ); +//PARAM( COPY_HEAD_LATENCY, 4, false ); +//PARAM( OnChipLinkLatency, 1, false ); +//PARAM( RecycleLatency, 10, false ); +//PARAM( L2_RECYCLE_LATENCY, 5, false ); +//PARAM( TIMER_LATENCY, 10000, false ); +//PARAM( TBE_RESPONSE_LATENCY, 1, false ); +//PARAM_BOOL( PERIODIC_TIMER_WAKEUPS, true, false ); // constants used by CMP protocols -PARAM( L1_REQUEST_LATENCY ); -PARAM( L2_REQUEST_LATENCY ); -PARAM_BOOL( SINGLE_ACCESS_L2_BANKS ); // hack to simulate multi-cycle L2 bank accesses +//PARAM( L1_REQUEST_LATENCY, 2, false ); +//PARAM( L2_REQUEST_LATENCY, 4, false ); +//PARAM_BOOL( SINGLE_ACCESS_L2_BANKS, true, false ); // hack to simulate multi-cycle L2 bank accesses // Ruby cycles between when a sequencer issues a miss it arrives at // the L1 cache controller -PARAM( SEQUENCER_TO_CONTROLLER_LATENCY ); +//PARAM( SequencerToControllerLatency, 4, false ); // Number of transitions each controller state machines can complete per cycle -PARAM( L1CACHE_TRANSITIONS_PER_RUBY_CYCLE ); -PARAM( L2CACHE_TRANSITIONS_PER_RUBY_CYCLE ); -PARAM( DIRECTORY_TRANSITIONS_PER_RUBY_CYCLE ); - -// Maximum number of requests (including prefetches) outstanding from -// the sequencer (Note: this also include items buffered in the store -// buffer) -PARAM( g_SEQUENCER_OUTSTANDING_REQUESTS ); +//PARAM( L1CacheTransitionsPerCycle, 32, false ); +//PARAM( L2CACHE_TRANSITIONS_PER_RUBY_CYCLE, 32, false ); +//PARAM( DirectoryTransitionsPerCycle, 32, false ); +//PARAM( DMATransitionsPerCycle, 1, false ); // Number of TBEs available for demand misses, prefetches, and replacements -PARAM( NUMBER_OF_TBES ); -PARAM( NUMBER_OF_L1_TBES ); -PARAM( NUMBER_OF_L2_TBES ); +//PARAM( NumberOfTBEs, 128, false ); +//PARAM( NumberOfL1TBEs, 32, false ); +//PARAM( NumberOfL2TBEs, 32, false ); // NOTE: Finite buffering allows us to simulate a wormhole routed network // with idealized flow control. All message buffers within the network (i.e. // the switch's input and output buffers) are set to the size specified below // by the PROTOCOL_BUFFER_SIZE -PARAM_BOOL( FINITE_BUFFERING ); -PARAM( FINITE_BUFFER_SIZE ); // Zero is unbounded buffers +//PARAM_BOOL( FiniteBuffering, false, false ); +//PARAM( FiniteBufferSize, 3, false ); // Zero is unbounded buffers // Number of requests buffered between the sequencer and the L1 conroller // This can be more accurately simulated in Opal, therefore it's set to an // infinite number // Only effects the simualtion when FINITE_BUFFERING is enabled -PARAM( PROCESSOR_BUFFER_SIZE ); +//PARAM( ProcessorBufferSize, 10, false ); // The PROTOCOL_BUFFER_SIZE limits the size of all other buffers connecting to // Controllers. Controlls the number of request issued by the L2 HW Prefetcher -PARAM( PROTOCOL_BUFFER_SIZE ); - -// Enable the TSO (Total Store Order) memory model -PARAM_BOOL( TSO ); // Note: This also disables the "write" STCs +//PARAM( ProtocolBufferSize, 32, false ); // NETWORK PARAMETERS // Network Topology: See TopologyType in external.sm for valid values -PARAM_STRING( g_NETWORK_TOPOLOGY ); +//PARAM_STRING( NetworkTopology, "PT_TO_PT", false ); // Cache Design specifies file prefix for topology -PARAM_STRING( g_CACHE_DESIGN ); - -PARAM( g_endpoint_bandwidth ); -PARAM_BOOL( g_adaptive_routing ); -PARAM( NUMBER_OF_VIRTUAL_NETWORKS ); -PARAM( FAN_OUT_DEGREE ); -PARAM_BOOL( g_PRINT_TOPOLOGY ); +//PARAM_STRING( CacheDesign, "NUCA", false ); -// transactional memory -PARAM( XACT_LENGTH ); -PARAM( XACT_SIZE ); -PARAM( ABORT_RETRY_TIME ); +//PARAM( EndpointBandwidth, 10000, false ); +//PARAM_BOOL( AdaptiveRouting, true, false ); +//PARAM( NumberOfVirtualNetworks, 6, false ); +//PARAM( FanOutDegree, 4, false ); +//PARAM_BOOL( PrintTopology, true, false ); // Princeton Network (Garnet) -PARAM_BOOL( g_GARNET_NETWORK ); -PARAM_BOOL( g_DETAIL_NETWORK ); -PARAM_BOOL( g_NETWORK_TESTING ); -PARAM( g_FLIT_SIZE ); -PARAM( g_NUM_PIPE_STAGES ); -PARAM( g_VCS_PER_CLASS ); -PARAM( g_BUFFER_SIZE ); +//PARAM_BOOL( UsingGarnetNetwork, true, false ); +//PARAM_BOOL( UsingDetailNetwork, false, false ); +//PARAM_BOOL( UsingNetworkTesting, false, false ); +//PARAM( FlitSize, 16, false ); +//PARAM( NumberOfPipeStages, 4, false ); +//PARAM( VCSPerClass, 4, false ); +//PARAM( BufferSize, 4, false ); // MemoryControl: -PARAM( MEM_BUS_CYCLE_MULTIPLIER ); -PARAM( BANKS_PER_RANK ); -PARAM( RANKS_PER_DIMM ); -PARAM( DIMMS_PER_CHANNEL ); -PARAM( BANK_BIT_0 ); -PARAM( RANK_BIT_0 ); -PARAM( DIMM_BIT_0 ); -PARAM( BANK_QUEUE_SIZE ); -PARAM( BANK_BUSY_TIME ); -PARAM( RANK_RANK_DELAY ); -PARAM( READ_WRITE_DELAY ); -PARAM( BASIC_BUS_BUSY_TIME ); -PARAM( MEM_CTL_LATENCY ); -PARAM( REFRESH_PERIOD ); -PARAM( TFAW ); -PARAM( MEM_RANDOM_ARBITRATE ); -PARAM( MEM_FIXED_DELAY ); +//PARAM( MEM_BUS_CYCLE_MULTIPLIER, 10, false ); +//PARAM( BANKS_PER_RANK, 8, false ); +//PARAM( RANKS_PER_DIMM, 2, false ); +//PARAM( DIMMS_PER_CHANNEL, 2, false ); +//PARAM( BANK_BIT_0, 8, false ); +//PARAM( RANK_BIT_0, 11, false ); +//PARAM( DIMM_BIT_0, 12, false ); +//PARAM( BANK_QUEUE_SIZE, 12, false ); +//PARAM( BankBusyTime, 11, false ); +//PARAM( RANK_RANK_DELAY, 1, false ); +//PARAM( READ_WRITE_DELAY, 2, false ); +//PARAM( BASIC_BUS_BUSY_TIME, 2, false ); +//PARAM( MEM_CTL_LATENCY, 12, false ); +//PARAM( REFRESH_PERIOD, 1560, false ); +//PARAM( TFAW, 0, false ); +//PARAM( MEM_RANDOM_ARBITRATE, 0, false ); +//PARAM( MEM_FIXED_DELAY, 0, false ); diff --git a/src/mem/ruby/config/defaults.rb b/src/mem/ruby/config/defaults.rb new file mode 100644 index 000000000..110bf4241 --- /dev/null +++ b/src/mem/ruby/config/defaults.rb @@ -0,0 +1,181 @@ +#!/usr/bin/ruby + + + +class NetPort < LibRubyObject + # number of transitions a SLICC state machine can transition per + # cycle + default_param :transitions_per_cycle, Integer, 32 + + # buffer_size limits the size of all other buffers connecting to + # SLICC Controllers. When 0, infinite buffering is used. + default_param :buffer_size, Integer, 32 + + # added by SS for TBE + default_param :number_of_TBEs, Integer, 128 + + default_param :recycle_latency, Integer, 10 +end + +class Sequencer < IfacePort + # Maximum number of requests (including prefetches) outstanding from + # the sequencer + default_param :max_outstanding_requests, Integer, 16 + + # Maximum number of cycles a request is can be outstanding before + # the Sequencer declares we're in deadlock/livelock + default_param :deadlock_threshold, Integer, 500000 + +end + +class Debug < LibRubyObject + # For debugging purposes, one can enable a trace of all the protocol + # state machine changes. Unfortunately, the code to generate the + # trace is protocol specific. To enable the code for some of the + # standard protocols, + # 1. change protocol_trace = true + # 2. enable debug in the Ruby Makefile + # 3. set start_time = 1 + default_param :protocol_trace, Boolean, false + + # a string for filtering debugging output (for all g_debug vars see Debug.h) + default_param :filter_string, String, "q" + + # filters debugging messages based on priority (low, med, high) + default_param :verbosity_string, String, "none" + + # filters debugging messages based on a ruby time + default_param :start_time, Integer, 1 + + # sends debugging messages to a output filename + default_param :output_filename, String, "" +end + +class Topology < LibRubyObject + # The default link latency between all nodes (internal and external) + # in the toplogy + default_param :link_latency, Integer, 1 + + # the bandwidth from an external network port to it's corresponding + # internal switch + default_param :external_bw, Integer, 64 + + # the bandwitch between internal switches in the network + default_param :internal_bw, Integer, 16 + + # indicates whether the topology config will be displayed in the + # stats file + default_param :print_config, Boolean, true +end + +class Network < LibRubyObject + default_param :endpoint_bandwidth, Integer, 10000 + default_param :adaptive_routing, Boolean, true + default_param :number_of_virtual_networks, Integer, 6 + default_param :fan_out_degree, Integer, 4 + + # default buffer size. Setting to 0 indicates infinite buffering + default_param :buffer_size, Integer, 3 + + # local memory latency ?? NetworkLinkLatency + default_param :link_latency, Integer, 1 + + # on chip latency + default_param :on_chip_latency, Integer, 1 +end + +class GarnetNetwork < Network + default_param :flit_size, Integer, 16 + default_param :number_of_pipe_stages, Integer, 4 + default_param :vcs_per_class, Integer, 4 + default_param :buffer_size, Integer, 4 + default_param :using_network_testing, Boolean, false +end + + + +#added by SS +class Tracer < LibRubyObject + default_param :warmup_length, Integer, 1000000 +end + +#added by SS +class Profiler < LibRubyObject + default_param :hot_lines, Boolean, false + default_param :all_instructions, Boolean, false +end + +#added by SS +class MI_example_CacheController < CacheController + default_param :issue_latency, Integer, 2 + default_param :cache_response_latency, Integer, 12 +end + +class MI_example_DirectoryController < DirectoryController + default_param :to_mem_ctrl_latency, Integer, 1 + default_param :directory_latency, Integer, 6 + default_param :memory_latency, Integer, 158 +end + + +#added by SS +class MemoryControl < LibRubyObject + + default_param :mem_bus_cycle_multiplier, Integer, 10 + default_param :banks_per_rank, Integer, 8 + default_param :ranks_per_dimm, Integer, 2 + default_param :dimms_per_channel, Integer, 2 + default_param :bank_bit_0, Integer, 8 + default_param :rank_bit_0, Integer, 11 + default_param :dimm_bit_0, Integer, 12 + default_param :bank_queue_size, Integer, 12 + default_param :bank_busy_time, Integer, 11 + default_param :rank_rank_delay, Integer, 1 + default_param :read_write_delay, Integer, 2 + default_param :basic_bus_busy_time, Integer, 2 + default_param :mem_ctl_latency, Integer, 12 + default_param :refresh_period, Integer, 1560 + default_param :tFaw, Integer, 0 + default_param :mem_random_arbitrate, Integer, 0 + default_param :mem_fixed_delay, Integer, 0 + +end + +class RubySystem + + # Random seed used by the simulation. If set to "rand", the seed + # will be set to the current wall clock at libruby + # initialization. Otherwise, set this to an integer. + default_param :random_seed, Object, "rand" + + # When set to true, the simulation will insert random delays on + # message enqueue times. Note that even if this is set to false, + # you can still have a non-deterministic simulation if random seed + # is set to "rand". This is because the Ruby swtiches use random + # link priority elevation + default_param :randomization, Boolean, false + + # tech_nm is the device size used to calculate latency and area + # information about system components + default_param :tech_nm, Integer, 45 + + # default frequency for the system + default_param :freq_mhz, Integer, 3000 + + # the default cache block size in the system + # libruby does not currently support different block sizes + # among different caches + # Must be a power of two + default_param :block_size_bytes, Integer, 64 + + # The default debug object. There shouldn't be a reason to ever + # change this line. To adjust debug paramters statically, adjust + # them in the Debug class above. To adjust these fields + # dynamically, access this RubySystem object, + # e.g. RubySystem.debug.protocol_trace = true + default_param :debug, Debug, Debug.new("dbg0") + default_param :tracer, Tracer, Tracer.new("tracer0") + + default_param :profiler, Profiler, Profiler.new("profiler0") +end + diff --git a/src/mem/ruby/config/libruby_cfg_test.cc b/src/mem/ruby/config/libruby_cfg_test.cc new file mode 100644 index 000000000..5d5b69d5f --- /dev/null +++ b/src/mem/ruby/config/libruby_cfg_test.cc @@ -0,0 +1,14 @@ + +#include +#include + +#include "../libruby.hh" + +int main(int argc, char* argv[]) +{ + assert(argc == 2); + const char* cfg_file = argv[1]; + + libruby_init(cfg_file); + libruby_print_config(std::cout); +} diff --git a/src/mem/ruby/config/print_cfg.rb b/src/mem/ruby/config/print_cfg.rb new file mode 100644 index 000000000..0a6d180d4 --- /dev/null +++ b/src/mem/ruby/config/print_cfg.rb @@ -0,0 +1,14 @@ + +ruby_cfg_file = nil +$stderr.puts $*.inspect +for i in 0..$*.size-1 do + if $*[i] == "-r" # ruby config file + i += 1 + ruby_cfg_file = $*[i] + break + end +end + +require ruby_cfg_file + +RubySystem.generateConfig diff --git a/src/mem/ruby/config/rubyconfig.defaults b/src/mem/ruby/config/rubyconfig.defaults index 873192c05..936a2f091 100644 --- a/src/mem/ruby/config/rubyconfig.defaults +++ b/src/mem/ruby/config/rubyconfig.defaults @@ -43,10 +43,6 @@ g_DEADLOCK_THRESHOLD: 500000 // (does not apply when running Opal) SIMICS_RUBY_MULTIPLIER: 4 -// corresponding parameter when using Opal+Ruby+Simics -OPAL_RUBY_MULTIPLIER: 1 - - // Ruby cycles between when a sequencer issues a request and it arrives at // the L1 cache controller // @@ -107,7 +103,7 @@ L2_CACHE_ASSOC: 4 L2_CACHE_NUM_SETS_BITS: 16 // 32 bits = 4 GB address space -g_MEMORY_SIZE_BYTES: 4294967296 +g_MEMORY_SIZE_BYTES: 1073741824 //4294967296 g_DATA_BLOCK_BYTES: 64 g_PAGE_SIZE_BYTES: 4096 g_REPLACEMENT_POLICY: PSEDUO_LRU // currently, only other option is LRU @@ -176,8 +172,6 @@ L1_REQUEST_LATENCY: 2 L2_REQUEST_LATENCY: 4 - - // Number of transitions each controller state machines can complete per cycle // i.e. the number of ports to each controller // L1cache is the sum of the L1I and L1D cache ports @@ -186,6 +180,7 @@ L1CACHE_TRANSITIONS_PER_RUBY_CYCLE: 32 // much greater constraint on the concurrency of a L2 cache bank L2CACHE_TRANSITIONS_PER_RUBY_CYCLE: 32 DIRECTORY_TRANSITIONS_PER_RUBY_CYCLE: 32 +DMA_TRANSITIONS_PER_RUBY_CYCLE: 1 // Number of TBEs available for demand misses, ALL prefetches, and replacements @@ -195,10 +190,6 @@ NUMBER_OF_TBES: 128 NUMBER_OF_L1_TBES: 32 NUMBER_OF_L2_TBES: 32 -// TSO is deprecated -TSO: false - - // ** INTERCONECT PARAMETERS ** // g_PRINT_TOPOLOGY: true @@ -207,7 +198,7 @@ g_CACHE_DESIGN: NUCA // specifies file prefix for FILE_SPECIFIED topology FAN_OUT_DEGREE: 4 // for HIERARCHICAL SWITCH topology g_adaptive_routing: true -NUMBER_OF_VIRTUAL_NETWORKS: 4 +NUMBER_OF_VIRTUAL_NETWORKS: 6 // bandwidth unit is 1/1000 byte per cycle. the following parameter is multiplied by // topology specific link weights @@ -240,57 +231,6 @@ PROTOCOL_BUFFER_SIZE: 32 SINGLE_ACCESS_L2_BANKS: true -// constants used by TM protocols -PROFILE_EXCEPTIONS: false -PROFILE_XACT: true -PROFILE_NONXACT: false -XACT_DEBUG: true -XACT_DEBUG_LEVEL: 1 -//XACT_MEMORY: true // set to true for TM protocols. set it HERE for lazy systems to register the proper SIMICS interfaces -XACT_MEMORY: false -XACT_ENABLE_TOURMALINE: false // perfect memory system -XACT_NUM_CURRENT: 0 // must be 0 -XACT_LAST_UPDATE: 0 // must be 0 -XACT_ISOLATION_CHECK: false // Checks whether each memory access preserves transaction isolation -PERFECT_FILTER: true // If true, use perfect physical read/write filters -READ_WRITE_FILTER: Perfect_ -PERFECT_VIRTUAL_FILTER: true // If true, use perfect virtual read/write filters -VIRTUAL_READ_WRITE_FILTER: Perfect_ -PERFECT_SUMMARY_FILTER: true // If true, use perfect summary read/write filters -SUMMARY_READ_WRITE_FILTER: Perfect_ -XACT_EAGER_CD: true -XACT_LAZY_VM: false -XACT_CONFLICT_RES: BASE -XACT_COMMIT_TOKEN_LATENCY: 0 -XACT_VISUALIZER: false -XACT_NO_BACKOFF: false -XACT_LOG_BUFFER_SIZE: 0 -XACT_STORE_PREDICTOR_ENTRIES: 256 -XACT_STORE_PREDICTOR_HISTORY: 256 -XACT_STORE_PREDICTOR_THRESHOLD: 4 -XACT_FIRST_ACCESS_COST: 0 -XACT_FIRST_PAGE_ACCESS_COST: 0 -ENABLE_MAGIC_WAITING: false -ENABLE_WATCHPOINT: false -XACT_ENABLE_VIRTUALIZATION_LOGTM_SE: false -// g_NETWORK_TOPOLOGY: FILE_SPECIFIED -// NUMBER_OF_VIRTUAL_NETWORKS: 5 -// L2_REQUEST_LATENCY: 15 -// SEQUENCER_TO_CONTROLLER_LATENCY: 3 -// L2_RESPONSE_LATENCY: 20 -// L2_TAG_LATENCY: 6 -// MEMORY_RESPONSE_LATENCY_MINUS_2: 448 -// RECYCLE_LATENCY: 1 -// g_MEMORY_SIZE_BYTES: 268435456 -// REMOVE_SINGLE_CYCLE_DCACHE_FAST_PATH: true - -// ATMTP -ATMTP_ENABLED: false -ATMTP_ABORT_ON_NON_XACT_INST: false -ATMTP_ALLOW_SAVE_RESTORE_IN_XACT: false -ATMTP_XACT_MAX_STORES: 32 -ATMTP_DEBUG_LEVEL: 0 - // MOESI_CMP_token parameters (some might be deprecated) g_FILTERING_ENABLED: false g_DISTRIBUTED_PERSISTENT_ENABLED: true @@ -321,7 +261,7 @@ g_hold_time: 5 g_wait_time: 5 // Princeton Network (Garnet) -g_GARNET_NETWORK: false +g_GARNET_NETWORK: true g_DETAIL_NETWORK: false g_NETWORK_TESTING: false g_FLIT_SIZE: 16 diff --git a/src/mem/ruby/config/tester.defaults b/src/mem/ruby/config/tester.defaults index 6ba655770..b30d1ba99 100644 --- a/src/mem/ruby/config/tester.defaults +++ b/src/mem/ruby/config/tester.defaults @@ -6,10 +6,11 @@ // Please: - Add new variables only to rubyconfig.defaults file. // - Change them here only when necessary. +g_SIMICS: false DATA_BLOCK: true RANDOMIZATION: true -g_SYNTHETIC_DRIVER: true -g_DETERMINISTIC_DRIVER: false +g_SYNTHETIC_DRIVER: false +g_DETERMINISTIC_DRIVER: true g_DEADLOCK_THRESHOLD: 500000 g_SpecifiedGenerator: DetermGETXGenerator @@ -28,23 +29,13 @@ L2_CACHE_NUM_SETS_BITS: 5 g_MEMORY_SIZE_BYTES: 1048576 -// XACT MEMORY -XACT_LENGTH: 2000 -XACT_SIZE: 1000 -ABORT_RETRY_TIME: 400 -XACT_ISOLATION_CHECK: true -L2CACHE_TRANSITIONS_PER_RUBY_CYCLE: 1000 -DIRECTORY_TRANSITIONS_PER_RUBY_CYCLE: 1000 -PERFECT_FILTER: true // If true, use perfect read/write filters -READ_WRITE_FILTER: Perfect_ - //g_NETWORK_TOPOLOGY: FILE_SPECIFIED RECYCLE_LATENCY: 1 //NUMBER_OF_VIRTUAL_NETWORKS: 5 //g_NUM_MEMORIES: 16 L2CACHE_TRANSITIONS_PER_RUBY_CYCLE: 1000 DIRECTORY_TRANSITIONS_PER_RUBY_CYCLE: 1000 -//g_PROCS_PER_CHIP: 16 +//g_PROCS_PER_CHIP: 2 //g_NUM_L2_BANKS: 16 //g_endpoint_bandwidth: 10000 //g_NUM_PROCESSORS: 16 diff --git a/src/mem/ruby/eventqueue/RubyEventQueue.cc b/src/mem/ruby/eventqueue/RubyEventQueue.cc index 4a979942f..1a4159f1d 100644 --- a/src/mem/ruby/eventqueue/RubyEventQueue.cc +++ b/src/mem/ruby/eventqueue/RubyEventQueue.cc @@ -49,7 +49,7 @@ RubyEventQueue::RubyEventQueue() RubyEventQueue::~RubyEventQueue() { - // delete m_prio_heap_ptr; + delete m_prio_heap_ptr; } void RubyEventQueue::init() @@ -91,7 +91,7 @@ void RubyEventQueue::triggerEvents(Time t) assert(thisNode.m_consumer_ptr != NULL); DEBUG_EXPR(EVENTQUEUE_COMP,MedPrio,*(thisNode.m_consumer_ptr)); DEBUG_EXPR(EVENTQUEUE_COMP,MedPrio,thisNode.m_time); - thisNode.m_consumer_ptr->triggerWakeup(); + thisNode.m_consumer_ptr->triggerWakeup(this); } m_globalTime = t; } @@ -107,7 +107,7 @@ void RubyEventQueue::triggerAllEvents() assert(thisNode.m_consumer_ptr != NULL); DEBUG_EXPR(EVENTQUEUE_COMP,MedPrio,*(thisNode.m_consumer_ptr)); DEBUG_EXPR(EVENTQUEUE_COMP,MedPrio,thisNode.m_time); - thisNode.m_consumer_ptr->triggerWakeup(); + thisNode.m_consumer_ptr->triggerWakeup(this); } } diff --git a/src/mem/ruby/filters/AbstractBloomFilter.hh b/src/mem/ruby/filters/AbstractBloomFilter.hh new file mode 100644 index 000000000..7e37a6e06 --- /dev/null +++ b/src/mem/ruby/filters/AbstractBloomFilter.hh @@ -0,0 +1,71 @@ + +/* + * Copyright (c) 1999-2008 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. + */ + +/* + * AbstractBloomFilter.hh + * + * Description: + * + * + */ + +#ifndef ABSTRACT_BLOOM_FILTER_H +#define ABSTRACT_BLOOM_FILTER_H + +#include "mem/ruby/common/Global.hh" +#include "mem/ruby/config/RubyConfig.hh" +#include "mem/ruby/common/Address.hh" + +class AbstractBloomFilter { +public: + + virtual ~AbstractBloomFilter() {}; + virtual void clear() = 0; + virtual void increment(const Address& addr) = 0; + virtual void decrement(const Address& addr) = 0; + virtual void merge(AbstractBloomFilter * other_filter) = 0; + virtual void set(const Address& addr) = 0; + virtual void unset(const Address& addr) = 0; + + virtual bool isSet(const Address& addr) = 0; + virtual int getCount(const Address& addr) = 0; + virtual int getTotalCount() = 0; + + virtual void print(ostream& out) const = 0; + + virtual int getIndex(const Address& addr) = 0; + virtual int readBit(const int index) = 0; + virtual void writeBit(const int index, const int value) = 0; + +private: + +}; + + +#endif diff --git a/src/mem/ruby/filters/BlockBloomFilter.cc b/src/mem/ruby/filters/BlockBloomFilter.cc new file mode 100644 index 000000000..9bf5b41c5 --- /dev/null +++ b/src/mem/ruby/filters/BlockBloomFilter.cc @@ -0,0 +1,147 @@ + +/* + * Copyright (c) 1999-2008 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. + */ + +/* + * BlockBloomFilter.cc + * + * Description: + * + * + */ + +#include "mem/ruby/filters/BlockBloomFilter.hh" +#include "mem/gems_common/Map.hh" +#include "mem/ruby/common/Address.hh" + +BlockBloomFilter::BlockBloomFilter(string str) +{ + string tail(str); + string head = string_split(tail, '_'); + + m_filter_size = atoi(head.c_str()); + m_filter_size_bits = log_int(m_filter_size); + + m_filter.setSize(m_filter_size); + + clear(); +} + +BlockBloomFilter::~BlockBloomFilter(){ +} + +void BlockBloomFilter::clear() +{ + for (int i = 0; i < m_filter_size; i++) { + m_filter[i] = 0; + } +} + +void BlockBloomFilter::increment(const Address& addr) +{ + // Not used +} + + +void BlockBloomFilter::decrement(const Address& addr) +{ + // Not used +} + +void BlockBloomFilter::merge(AbstractBloomFilter * other_filter) +{ + // TODO +} + +void BlockBloomFilter::set(const Address& addr) +{ + int i = get_index(addr); + m_filter[i] = 1; +} + +void BlockBloomFilter::unset(const Address& addr) +{ + int i = get_index(addr); + m_filter[i] = 0; +} + +bool BlockBloomFilter::isSet(const Address& addr) +{ + int i = get_index(addr); + return (m_filter[i]); +} + + +int BlockBloomFilter::getCount(const Address& addr) +{ + return m_filter[get_index(addr)]; +} + +int BlockBloomFilter::getTotalCount() +{ + int count = 0; + + for (int i = 0; i < m_filter_size; i++) { + if (m_filter[i]) { + count++; + } + } + return count; +} + +int BlockBloomFilter::getIndex(const Address& addr) +{ + return get_index(addr); +} + +void BlockBloomFilter::print(ostream& out) const +{ +} + +int BlockBloomFilter::readBit(const int index) { + return m_filter[index]; +} + +void BlockBloomFilter::writeBit(const int index, const int value) { + m_filter[index] = value; +} + +int BlockBloomFilter::get_index(const Address& addr) +{ + // Pull out some bit field ==> B1 + // Pull out additional bits, not the same as B1 ==> B2 + // XOR B1 and B2 to get hash index + physical_address_t block_bits = addr.bitSelect( RubySystem::getBlockSizeBits(), 2*RubySystem::getBlockSizeBits() - 1); + int offset = 5; + physical_address_t other_bits = addr.bitSelect( 2*RubySystem::getBlockSizeBits() + offset, 2*RubySystem::getBlockSizeBits() + offset + m_filter_size_bits - 1); + int index = block_bits ^ other_bits; + assert(index < m_filter_size); + return index; +} + + diff --git a/src/mem/ruby/filters/BlockBloomFilter.hh b/src/mem/ruby/filters/BlockBloomFilter.hh new file mode 100644 index 000000000..205b4172d --- /dev/null +++ b/src/mem/ruby/filters/BlockBloomFilter.hh @@ -0,0 +1,82 @@ + +/* + * Copyright (c) 1999-2008 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. + */ + +/* + * BlockBloomFilter.hh + * + * Description: + * + * + */ + +#ifndef BLOCK_BLOOM_FILTER_H +#define BLOCK_BLOOM_FILTER_H + +#include "mem/gems_common/Map.hh" +#include "mem/ruby/common/Global.hh" +#include "mem/ruby/config/RubyConfig.hh" +#include "mem/ruby/common/Address.hh" +#include "mem/ruby/filters/AbstractBloomFilter.hh" + +class BlockBloomFilter : public AbstractBloomFilter { +public: + + ~BlockBloomFilter(); + BlockBloomFilter(string config); + + void clear(); + void increment(const Address& addr); + void decrement(const Address& addr); + void merge(AbstractBloomFilter * other_filter); + void set(const Address& addr); + void unset(const Address& addr); + + bool isSet(const Address& addr); + int getCount(const Address& addr); + int getTotalCount(); + int getIndex(const Address& addr); + int readBit(const int index); + void writeBit(const int index, const int value); + + void print(ostream& out) const; + +private: + + int get_index(const Address& addr); + + Vector m_filter; + int m_filter_size; + int m_filter_size_bits; + + int m_count_bits; + int m_count; +}; + + +#endif diff --git a/src/mem/ruby/filters/BulkBloomFilter.cc b/src/mem/ruby/filters/BulkBloomFilter.cc new file mode 100644 index 000000000..264b4201c --- /dev/null +++ b/src/mem/ruby/filters/BulkBloomFilter.cc @@ -0,0 +1,232 @@ + +/* + * Copyright (c) 1999-2008 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. + */ + +/* + * BulkBloomFilter.cc + * + * Description: + * + * + */ + +#include "mem/ruby/filters/BulkBloomFilter.hh" +#include "mem/gems_common/Map.hh" +#include "mem/ruby/common/Address.hh" + +BulkBloomFilter::BulkBloomFilter(string str) +{ + string tail(str); + string head = string_split(tail, '_'); + + m_filter_size = atoi(head.c_str()); + m_filter_size_bits = log_int(m_filter_size); + // split the filter bits in half, c0 and c1 + m_sector_bits = m_filter_size_bits - 1; + + m_temp_filter.setSize(m_filter_size); + m_filter.setSize(m_filter_size); + clear(); + + // clear temp filter + for(int i=0; i < m_filter_size; ++i){ + m_temp_filter[i] = 0; + } +} + +BulkBloomFilter::~BulkBloomFilter(){ + +} + +void BulkBloomFilter::clear() +{ + for (int i = 0; i < m_filter_size; i++) { + m_filter[i] = 0; + } +} + +void BulkBloomFilter::increment(const Address& addr) +{ + // Not used +} + + +void BulkBloomFilter::decrement(const Address& addr) +{ + // Not used +} + +void BulkBloomFilter::merge(AbstractBloomFilter * other_filter) +{ + // TODO +} + +void BulkBloomFilter::set(const Address& addr) +{ + // c0 contains the cache index bits + int set_bits = m_sector_bits; + int block_bits = RubySystem::getBlockSizeBits(); + int c0 = addr.bitSelect( block_bits, block_bits + set_bits - 1); + // c1 contains the lower m_sector_bits permuted bits + //Address permuted_bits = permute(addr); + //int c1 = permuted_bits.bitSelect(0, set_bits-1); + int c1 = addr.bitSelect( block_bits+set_bits, (block_bits+2*set_bits) - 1); + //ASSERT(c0 < (m_filter_size/2)); + //ASSERT(c0 + (m_filter_size/2) < m_filter_size); + //ASSERT(c1 < (m_filter_size/2)); + // set v0 bit + m_filter[c0 + (m_filter_size/2)] = 1; + // set v1 bit + m_filter[c1] = 1; +} + +void BulkBloomFilter::unset(const Address& addr) +{ + // not used +} + +bool BulkBloomFilter::isSet(const Address& addr) +{ + // c0 contains the cache index bits + int set_bits = m_sector_bits; + int block_bits = RubySystem::getBlockSizeBits(); + int c0 = addr.bitSelect( block_bits, block_bits + set_bits - 1); + // c1 contains the lower 10 permuted bits + //Address permuted_bits = permute(addr); + //int c1 = permuted_bits.bitSelect(0, set_bits-1); + int c1 = addr.bitSelect( block_bits+set_bits, (block_bits+2*set_bits) - 1); + //ASSERT(c0 < (m_filter_size/2)); + //ASSERT(c0 + (m_filter_size/2) < m_filter_size); + //ASSERT(c1 < (m_filter_size/2)); + // set v0 bit + m_temp_filter[c0 + (m_filter_size/2)] = 1; + // set v1 bit + m_temp_filter[c1] = 1; + + // perform filter intersection. If any c part is 0, no possibility of address being in signature. + // get first c intersection part + bool zero = false; + for(int i=0; i < m_filter_size/2; ++i){ + // get intersection of signatures + m_temp_filter[i] = m_temp_filter[i] && m_filter[i]; + zero = zero || m_temp_filter[i]; + } + zero = !zero; + if(zero){ + // one section is zero, no possiblility of address in signature + // reset bits we just set + m_temp_filter[c0 + (m_filter_size/2)] = 0; + m_temp_filter[c1] = 0; + return false; + } + + // check second section + zero = false; + for(int i=m_filter_size/2; i < m_filter_size; ++i){ + // get intersection of signatures + m_temp_filter[i] = m_temp_filter[i] && m_filter[i]; + zero = zero || m_temp_filter[i]; + } + zero = !zero; + if(zero){ + // one section is zero, no possiblility of address in signature + m_temp_filter[c0 + (m_filter_size/2)] = 0; + m_temp_filter[c1] = 0; + return false; + } + // one section has at least one bit set + m_temp_filter[c0 + (m_filter_size/2)] = 0; + m_temp_filter[c1] = 0; + return true; +} + + +int BulkBloomFilter::getCount(const Address& addr) +{ + // not used + return 0; +} + +int BulkBloomFilter::getTotalCount() +{ + int count = 0; + for (int i = 0; i < m_filter_size; i++) { + if (m_filter[i]) { + count++; + } + } + return count; +} + +int BulkBloomFilter::getIndex(const Address& addr) +{ + return get_index(addr); +} + +int BulkBloomFilter::readBit(const int index) { + return 0; + // TODO +} + +void BulkBloomFilter::writeBit(const int index, const int value) { + // TODO +} + +void BulkBloomFilter::print(ostream& out) const +{ +} + +int BulkBloomFilter::get_index(const Address& addr) +{ + return addr.bitSelect( RubySystem::getBlockSizeBits(), RubySystem::getBlockSizeBits() + m_filter_size_bits - 1); +} + +Address BulkBloomFilter::permute(const Address & addr){ + // permutes the original address bits according to Table 5 + int block_offset = RubySystem::getBlockSizeBits(); + physical_address_t part1 = addr.bitSelect( block_offset, block_offset + 6 ); + physical_address_t part2 = addr.bitSelect( block_offset + 9, block_offset + 9 ); + physical_address_t part3 = addr.bitSelect( block_offset + 11, block_offset + 11 ); + physical_address_t part4 = addr.bitSelect( block_offset + 17, block_offset + 17 ); + physical_address_t part5 = addr.bitSelect( block_offset + 7, block_offset + 8 ); + physical_address_t part6 = addr.bitSelect( block_offset + 10, block_offset + 10 ); + physical_address_t part7 = addr.bitSelect( block_offset + 12, block_offset + 12 ); + physical_address_t part8 = addr.bitSelect( block_offset + 13, block_offset + 13 ); + physical_address_t part9 = addr.bitSelect( block_offset + 15, block_offset + 16 ); + physical_address_t part10 = addr.bitSelect( block_offset + 18, block_offset + 20 ); + physical_address_t part11 = addr.bitSelect( block_offset + 14, block_offset + 14 ); + + physical_address_t result = (part1 << 14 ) | (part2 << 13 ) | (part3 << 12 ) | (part4 << 11 ) | (part5 << 9) | (part6 << 8) + | (part7 << 7) | (part8 << 6) | (part9 << 4) | (part10 << 1) | (part11); + // assume 32 bit addresses (both virtual and physical) + // select the remaining high-order 11 bits + physical_address_t remaining_bits = (addr.bitSelect( block_offset + 21, 31 )) << 21; + result = result | remaining_bits; + + return Address(result); +} diff --git a/src/mem/ruby/filters/BulkBloomFilter.hh b/src/mem/ruby/filters/BulkBloomFilter.hh new file mode 100644 index 000000000..2dbdb6612 --- /dev/null +++ b/src/mem/ruby/filters/BulkBloomFilter.hh @@ -0,0 +1,87 @@ + +/* + * Copyright (c) 1999-2008 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. + */ + +/* + * BulkBloomFilter.hh + * + * Description: + * + * + */ + +#ifndef BULK_BLOOM_FILTER_H +#define BULK_BLOOM_FILTER_H + +#include "mem/gems_common/Map.hh" +#include "mem/ruby/common/Global.hh" +#include "mem/ruby/config/RubyConfig.hh" +#include "mem/ruby/common/Address.hh" +#include "mem/ruby/filters/AbstractBloomFilter.hh" + +class BulkBloomFilter : public AbstractBloomFilter { +public: + + ~BulkBloomFilter(); + BulkBloomFilter(string config); + + void clear(); + void increment(const Address& addr); + void decrement(const Address& addr); + void merge(AbstractBloomFilter * other_filter); + void set(const Address& addr); + void unset(const Address& addr); + + bool isSet(const Address& addr); + int getCount(const Address& addr); + int getTotalCount(); + int getIndex(const Address& addr); + int readBit(const int index); + void writeBit(const int index, const int value); + + void print(ostream& out) const; + +private: + + int get_index(const Address& addr); + Address permute(const Address & addr); + + Vector m_filter; + Vector m_temp_filter; + + int m_filter_size; + int m_filter_size_bits; + + int m_sector_bits; + + int m_count_bits; + int m_count; +}; + + +#endif diff --git a/src/mem/ruby/filters/GenericBloomFilter.cc b/src/mem/ruby/filters/GenericBloomFilter.cc new file mode 100644 index 000000000..f4198ef40 --- /dev/null +++ b/src/mem/ruby/filters/GenericBloomFilter.cc @@ -0,0 +1,150 @@ + +/* + * Copyright (c) 1999-2008 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. + */ + +/* + * GenericBloomFilter.hh + * + * Description: + * + * + */ + +#include "mem/ruby/common/Global.hh" +#include "mem/ruby/config/RubyConfig.hh" +#include "mem/ruby/common/Address.hh" + +#include "mem/ruby/filters/GenericBloomFilter.hh" +#include "mem/ruby/filters/LSB_CountingBloomFilter.hh" +#include "mem/ruby/filters/NonCountingBloomFilter.hh" +#include "mem/ruby/filters/BulkBloomFilter.hh" +#include "mem/ruby/filters/BlockBloomFilter.hh" +#include "mem/ruby/filters/MultiGrainBloomFilter.hh" +#include "mem/ruby/filters/MultiBitSelBloomFilter.hh" +#include "mem/ruby/filters/H3BloomFilter.hh" + +GenericBloomFilter::GenericBloomFilter(string config) +{ + string tail(config); + string head = string_split(tail,'_'); + + if (head == "LSB_Counting" ) { + m_filter = new LSB_CountingBloomFilter(tail); + } + else if(head == "NonCounting" ) { + m_filter = new NonCountingBloomFilter(tail); + } + else if(head == "Bulk" ) { + m_filter = new BulkBloomFilter(tail); + } + else if(head == "Block") { + m_filter = new BlockBloomFilter(tail); + } + else if(head == "Multigrain"){ + m_filter = new MultiGrainBloomFilter(tail); + } + else if(head == "MultiBitSel"){ + m_filter = new MultiBitSelBloomFilter(tail); + } + else if(head == "H3"){ + m_filter = new H3BloomFilter(tail); + } + else { + assert(0); + } +} + +GenericBloomFilter::~GenericBloomFilter() +{ + delete m_filter; +} + +void GenericBloomFilter::clear() +{ + m_filter->clear(); +} + +void GenericBloomFilter::increment(const Address& addr) +{ + m_filter->increment(addr); +} + +void GenericBloomFilter::decrement(const Address& addr) +{ + m_filter->decrement(addr); +} + +void GenericBloomFilter::merge(GenericBloomFilter * other_filter) +{ + m_filter->merge(other_filter->getFilter()); +} + +void GenericBloomFilter::set(const Address& addr) +{ + m_filter->set(addr); +} + +void GenericBloomFilter::unset(const Address& addr) +{ + m_filter->unset(addr); +} + +bool GenericBloomFilter::isSet(const Address& addr) +{ + return m_filter->isSet(addr); +} + +int GenericBloomFilter::getCount(const Address& addr) +{ + return m_filter->getCount(addr); +} + +int GenericBloomFilter::getTotalCount() +{ + return m_filter->getTotalCount(); +} + +int GenericBloomFilter::getIndex(const Address& addr) +{ + return m_filter->getIndex(addr); +} + +int GenericBloomFilter::readBit(const int index) { + return m_filter->readBit(index); +} + +void GenericBloomFilter::writeBit(const int index, const int value) { + m_filter->writeBit(index, value); +} + +void GenericBloomFilter::print(ostream& out) const +{ + return m_filter->print(out); +} + + diff --git a/src/mem/ruby/filters/GenericBloomFilter.hh b/src/mem/ruby/filters/GenericBloomFilter.hh new file mode 100644 index 000000000..4ff65f404 --- /dev/null +++ b/src/mem/ruby/filters/GenericBloomFilter.hh @@ -0,0 +1,94 @@ + +/* + * Copyright (c) 1999-2008 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. + */ + +/* + * GenericBloomFilter.hh + * + * Description: + * + * + */ + +#ifndef GENERIC_BLOOM_FILTER_H +#define GENERIC_BLOOM_FILTER_H + +#include "mem/ruby/common/Global.hh" +#include "mem/ruby/config/RubyConfig.hh" +#include "mem/ruby/common/Address.hh" +#include "mem/ruby/filters/AbstractBloomFilter.hh" + +class GenericBloomFilter { +public: + + // Constructors + GenericBloomFilter(string config); + + void clear(); + void increment(const Address& addr); + void decrement(const Address& addr); + void merge(GenericBloomFilter * other_filter); + void set(const Address& addr); + void unset(const Address& addr); + AbstractBloomFilter * getFilter(){ + return m_filter; + } + + bool isSet(const Address& addr); + + int getCount(const Address& addr); + + int getTotalCount(); + + int getIndex(const Address& addr); + int readBit(const int index); + void writeBit(const int index, const int value); + + void print(ostream& out) const; + void printConfig(ostream& out) { out << "GenericBloomFilter" << endl; } + + // Destructor + ~GenericBloomFilter(); + + +private: + + AbstractBloomFilter* m_filter; +}; + +// Output operator definition +extern inline +ostream& operator<<(ostream& out, const GenericBloomFilter& obj) +{ + obj.print(out); + out << flush; + return out; +} + + +#endif diff --git a/src/mem/ruby/filters/H3BloomFilter.cc b/src/mem/ruby/filters/H3BloomFilter.cc new file mode 100644 index 000000000..2f5a0fc64 --- /dev/null +++ b/src/mem/ruby/filters/H3BloomFilter.cc @@ -0,0 +1,210 @@ + +/* + * Copyright (c) 1999-2008 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. + */ + +/* + * NonCountingBloomFilter.cc + * + * Description: + * + * + */ + +#include "mem/ruby/filters/H3BloomFilter.hh" +#include "mem/gems_common/Map.hh" +#include "mem/ruby/common/Address.hh" + +H3BloomFilter::H3BloomFilter(string str) +{ + //TODO: change this ugly init code... + primes_list[0] = 9323; + primes_list[1] = 11279; + primes_list[2] = 10247; + primes_list[3] = 30637; + primes_list[4] = 25717; + primes_list[5] = 43711; + + mults_list[0] = 255; + mults_list[1] = 29; + mults_list[2] = 51; + mults_list[3] = 3; + mults_list[4] = 77; + mults_list[5] = 43; + + adds_list[0] = 841; + adds_list[1] = 627; + adds_list[2] = 1555; + adds_list[3] = 241; + adds_list[4] = 7777; + adds_list[5] = 65931; + + + + string tail(str); + string head = string_split(tail, '_'); + + // head contains filter size, tail contains bit offset from block number + m_filter_size = atoi(head.c_str()); + + head = string_split(tail, '_'); + m_num_hashes = atoi(head.c_str()); + + if(tail == "Regular") { + isParallel = false; + } else if (tail == "Parallel") { + isParallel = true; + } else { + cout << "ERROR: Incorrect config string for MultiHash Bloom! :" << str << endl; + assert(0); + } + + m_filter_size_bits = log_int(m_filter_size); + + m_par_filter_size = m_filter_size/m_num_hashes; + m_par_filter_size_bits = log_int(m_par_filter_size); + + m_filter.setSize(m_filter_size); + clear(); +} + +H3BloomFilter::~H3BloomFilter(){ +} + +void H3BloomFilter::clear() +{ + for (int i = 0; i < m_filter_size; i++) { + m_filter[i] = 0; + } +} + +void H3BloomFilter::increment(const Address& addr) +{ + // Not used +} + + +void H3BloomFilter::decrement(const Address& addr) +{ + // Not used +} + +void H3BloomFilter::merge(AbstractBloomFilter * other_filter){ + // assumes both filters are the same size! + H3BloomFilter * temp = (H3BloomFilter*) other_filter; + for(int i=0; i < m_filter_size; ++i){ + m_filter[i] |= (*temp)[i]; + } + +} + +void H3BloomFilter::set(const Address& addr) +{ + for (int i = 0; i < m_num_hashes; i++) { + int idx = get_index(addr, i); + m_filter[idx] = 1; + + //Profile hash value distribution + //g_system_ptr->getProfiler()->getXactProfiler()->profileHashValue(i, idx); // gem5:Arka decomissiong of log_tm + } +} + +void H3BloomFilter::unset(const Address& addr) +{ + cout << "ERROR: Unset should never be called in a Bloom filter"; + assert(0); +} + +bool H3BloomFilter::isSet(const Address& addr) +{ + bool res = true; + + for (int i=0; i < m_num_hashes; i++) { + int idx = get_index(addr, i); + res = res && m_filter[idx]; + } + return res; +} + + +int H3BloomFilter::getCount(const Address& addr) +{ + return isSet(addr)? 1: 0; +} + +int H3BloomFilter::getIndex(const Address& addr) +{ + return 0; +} + +int H3BloomFilter::readBit(const int index) { + return 0; +} + +void H3BloomFilter::writeBit(const int index, const int value) { + +} + +int H3BloomFilter::getTotalCount() +{ + int count = 0; + + for (int i = 0; i < m_filter_size; i++) { + count += m_filter[i]; + } + return count; +} + +void H3BloomFilter::print(ostream& out) const +{ +} + +int H3BloomFilter::get_index(const Address& addr, int i) +{ + uint64 x = addr.getLineAddress(); + //uint64 y = (x*mults_list[i] + adds_list[i]) % primes_list[i]; + int y = hash_H3(x,i); + + if(isParallel) { + return (y % m_par_filter_size) + i*m_par_filter_size; + } else { + return y % m_filter_size; + } +} + +int H3BloomFilter::hash_H3(uint64 value, int index) { + uint64 mask = 1; + uint64 val = value; + int result = 0; + + for(int i = 0; i < 64; i++) { + if(val&mask) result ^= H3[i][index]; + val = val >> 1; + } + return result; + } + diff --git a/src/mem/ruby/filters/H3BloomFilter.hh b/src/mem/ruby/filters/H3BloomFilter.hh new file mode 100644 index 000000000..70f8a4506 --- /dev/null +++ b/src/mem/ruby/filters/H3BloomFilter.hh @@ -0,0 +1,1258 @@ + +/* + * Copyright (c) 1999-2008 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. + */ + +/* + * H3BloomFilter.hh + * + * Description: + * + * + */ + +#ifndef H3_BLOOM_FILTER_H +#define H3_BLOOM_FILTER_H + +#include "mem/gems_common/Map.hh" +#include "mem/ruby/common/Global.hh" +#include "mem/ruby/system/System.hh" +#include "mem/ruby/profiler/Profiler.hh" +#include "mem/ruby/config/RubyConfig.hh" +#include "mem/ruby/common/Address.hh" +#include "mem/ruby/filters/AbstractBloomFilter.hh" + +static int H3[64][16] = { +{ +33268410, +395488709, +311024285, +456111753, +181495008, +119997521, +220697869, +433891432, +755927921, +515226970, +719448198, +349842774, +269183649, +463275672, +429800228, +521598937 +}, +{ +628677802, +820947732, +809435975, +1024657192, +887631270, +412050215, +391365090, +324227279, +318338329, +1038393087, +489807930, +387366128, +518096428, +324184340, +429376066, +447109279 +}, +{ +599747653, +404960623, +103933604, +946416030, +656460913, +925957005, +1047665689, +163552053, +88359290, +841315415, +899833584, +1067336680, +348549994, +464045876, +270252128, +829897652 +}, +{ +215495230, +966696438, +82589012, +750102795, +909780866, +920285789, +769759214, +331966823, +939936006, +439950703, +883794828, +1009277508, +61634610, +741444350, +98689608, +524144422 +}, +{ +93868534, +196958667, +774076619, +327921978, +122538783, +879785030, +690748527, +3498564, +83163077, +1027963025, +582088444, +466152216, +312424878, +550064499, +646612667, +561099434 +}, +{ +1002047931, +395477707, +821317480, +890482112, +697094476, +263813044, +840275189, +469664185, +795625845, +211504898, +99204277, +1004491153, +725930417, +1064479221, +893834767, +839719181 +}, +{ +278507126, +985111995, +706462983, +1042178726, +123281719, +963778122, +500881056, +726291104, +134293026, +568379664, +317050609, +533470307, +1022365922, +197645211, +315125721, +634827678 +}, +{ +219227366, +553960647, +870169525, +322232839, +508322497, +648672696, +249405795, +883596102, +476433133, +541372919, +646647793, +1042679515, +43242483, +600187508, +499866821, +135713210 +}, +{ +52837162, +96966684, +401840460, +1071661176, +733560065, +150035417, +341319946, +811582750, +636173904, +519054065, +196321433, +1028294565, +882204070, +522965093, +48884074, +117810166 +}, +{ +650860353, +789534698, +328813544, +473250022, +143128306, +173196006, +846958825, +174632187, +683273509, +405459497, +787235556, +773873501, +240110267, +426797736, +92043842, +711789240 +}, +{ +586637493, +5059646, +398035664, +6686087, +498300175, +948278148, +681227731, +592751744, +572019677, +558044722, +589368271, +695745538, +1073416749, +529192035, +550984939, +1070620580 +}, +{ +102904663, +647598516, +758863940, +313426443, +76504114, +1050747783, +708436441, +563815069, +224107668, +875925186, +167675944, +926209739, +279737287, +1040288182, +768184312, +371708956 +}, +{ +683968868, +1027427757, +180781926, +742898864, +624078545, +645659833, +577225838, +987150210, +723410002, +224013421, +993286634, +33188488, +247264323, +888018697, +38048664, +189037096 +}, +{ +475612146, +426739285, +873726278, +529192871, +607715202, +388486246, +987001312, +474493980, +259747270, +417465536, +217062395, +392858482, +563810075, +137852805, +1051814153, +72895217 +}, +{ +71277086, +785496675, +500608842, +89633426, +274085706, +248467935, +838061983, +48106147, +773662506, +49545328, +9071573, +100739031, +602018002, +904371654, +534132064, +332211304 +}, +{ +401893602, +735125342, +775548339, +210224843, +256081130, +482894412, +350801633, +1035713633, +429458128, +327281409, +739927752, +359327650, +886942880, +847691759, +752417993, +359445596 +}, +{ +267472014, +1050659620, +1068232362, +1049684368, +17130239, +690524969, +793224378, +14455158, +423092885, +873853424, +430535778, +7867877, +309731959, +370260786, +862353083, +403906850 +}, +{ +993077283, +218812656, +389234651, +393202875, +413116501, +263300295, +470013158, +592730725, +441847172, +732392823, +407574059, +875664777, +271347307, +792954404, +554774761, +1022424300 +}, +{ +675919719, +637054073, +784720745, +149714381, +813144874, +502525801, +635436670, +1003196587, +160786091, +947509775, +969788637, +26854073, +257964369, +63898568, +539767732, +772364518 +}, +{ +943076868, +1021732472, +697575075, +15843624, +617573396, +534113303, +122953324, +964873912, +942995378, +87830944, +1012914818, +455484661, +592160054, +599844284, +810394353, +836812568 +}, +{ +688992674, +279465370, +731582262, +687883235, +438178468, +80493001, +342701501, +663561405, +23360106, +531315007, +508931618, +36294623, +231216223, +840438413, +255665680, +663205938 +}, +{ +857265418, +552630887, +8173237, +792122963, +210140052, +823124938, +667709953, +751538219, +991957789, +462064153, +19070176, +726604748, +714567823, +151147895, +1012619677, +697114353 +}, +{ +467105652, +683256174, +702387467, +28730434, +549942998, +48712701, +960519696, +1008345587, +679267717, +370932249, +880419471, +352141567, +331640403, +598772468, +95160685, +812053015 +}, +{ +1053491323, +430526562, +1014938507, +109685515, +765949103, +177288303, +1034642653, +485421658, +71850281, +981034542, +61620389, +601367920, +504420930, +220599168, +583051998, +158735752 +}, +{ +103033901, +522494916, +658494760, +959206022, +931348143, +834510661, +21542994, +189699884, +679327018, +171983002, +96774168, +456133168, +543103352, +923945936, +970074188, +643658485 +}, +{ +566379913, +805798263, +840662512, +820206124, +796507494, +223712542, +118811519, +662246595, +809326534, +416471323, +748027186, +161169753, +739149488, +276330378, +924837051, +964873733 +}, +{ +585882743, +135502711, +3386031, +625631285, +1068193307, +270342640, +432739484, +556606453, +826419155, +1038540977, +158000202, +69109538, +207087256, +298111218, +678046259, +184611498 +}, +{ +305310710, +46237988, +855726974, +735975153, +930663798, +425764232, +104362407, +391371443, +867622101, +71645091, +61824734, +661902640, +293738633, +309416189, +281710675, +879317360 +}, +{ +398146324, +398293087, +689145387, +1038451703, +521637478, +516134620, +314658937, +830334981, +583400300, +340083705, +68029852, +675389876, +994635780, +788959180, +406967042, +74403607 +}, +{ +69463153, +744427484, +191639960, +590927798, +969916795, +546846769, +728756758, +889355646, +520855076, +136068426, +776132410, +189663815, +252051082, +533662856, +362198652, +1026161384 +}, +{ +584984279, +1004834381, +568439705, +834508761, +21812513, +670870173, +1052043300, +341868768, +473755574, +124339439, +36193947, +437997647, +137419489, +58705193, +337793711, +340738909 +}, +{ +898051466, +512792906, +234874060, +655358775, +683745319, +671676404, +428888546, +639928192, +672697722, +176477579, +747020991, +758211282, +443045009, +205395173, +1016944273, +5584717 +}, +{ +156038300, +138620174, +588466825, +1061494056, +1013672100, +1064257198, +881417791, +839470738, +83519030, +100875683, +237486447, +461483733, +681527127, +777996147, +574635362, +815974538 +}, +{ +184168473, +519509808, +62531892, +51821173, +43787358, +385711644, +141325169, +36069511, +584183031, +571372909, +671503175, +226486781, +194932686, +1045460970, +753718579, +331442433 +}, +{ +73065106, +1015327221, +630916840, +1058053470, +306737587, +296343219, +907194989, +920172546, +224516225, +818625553, +551143849, +634570650, +432966225, +756438259, +939564853, +767999933 +}, +{ +884775648, +394862257, +446787794, +219833788, +727195727, +728122304, +249888353, +732947974, +289908868, +448282580, +618161877, +898939716, +739554163, +860631799, +1058977530, +86916736 +}, +{ +143850006, +352708694, +200194048, +979764914, +629404175, +546279766, +72106714, +860980514, +313190585, +897143111, +308425797, +953791785, +349924906, +221457005, +950588925, +908254505 +}, +{ +950032043, +829868728, +68623614, +714624605, +69760597, +297275854, +355894016, +985369737, +882852618, +864071289, +958512902, +950910111, +991368991, +829645051, +434698210, +771350575 +}, +{ +552695074, +319195551, +80297396, +496413831, +944046531, +621525571, +617653363, +416729825, +441842808, +9847464, +99420657, +1033914550, +812966458, +937053011, +673390195, +934577365 +}, +{ +1034695843, +190969665, +332900185, +51897434, +523888639, +883512843, +146908572, +506785674, +565814307, +692255649, +314052926, +826386588, +430691325, +866927620, +413880214, +936474339 +}, +{ +129380164, +741739952, +1013703462, +494392795, +957214600, +1010879043, +931790677, +94551922, +988065869, +120637871, +882506912, +395075379, +210570485, +812422692, +910383687, +817722285 +}, +{ +51850866, +283408630, +1053047202, +858940389, +818507731, +477082181, +353546901, +993324368, +407093779, +231608253, +1067319867, +73159811, +429792535, +971320614, +565699344, +718823399 +}, +{ +408185106, +491493570, +596050720, +310776444, +703628192, +454438809, +523988035, +728512200, +686012353, +976339656, +72816924, +116926720, +165866591, +452043792, +866943072, +968545481 +}, +{ +443231195, +905907843, +1061421320, +746360489, +1043120338, +1069659155, +463359031, +688303227, +186550710, +155347339, +1044842421, +1005904570, +69332909, +706951903, +422513657, +882038450 +}, +{ +430990623, +946501980, +742556791, +278398643, +183759217, +659404315, +279754382, +1069347846, +843746517, +222777670, +990835599, +548741637, +129220580, +1392170, +1032654091, +894058935 +}, +{ +452042227, +751640705, +259481376, +765824585, +145991469, +1013683228, +1055491225, +536379588, +392593350, +913368594, +1029429776, +226857786, +31505342, +1054416381, +32341741, +687106649 +}, +{ +404750944, +811417027, +869530820, +773491060, +810901282, +979340397, +1036910290, +461764404, +834235095, +765695033, +604692390, +452158120, +928988098, +442719218, +1024059719, +167723114 +}, +{ +974245177, +1046377300, +1003424287, +787349855, +336314155, +875074696, +1018462718, +890313003, +367376809, +86355556, +1020618772, +890710345, +444741481, +373230261, +767064947, +840920177 +}, +{ +719581124, +431808156, +138301690, +668222575, +497413494, +740492013, +485033226, +125301442, +831265111, +879071459, +341690480, +152975256, +850330086, +717444507, +694225877, +785340566 +}, +{ +1032766252, +140959364, +737474726, +1062767538, +364464647, +331414723, +356152634, +642832379, +158733632, +374691640, +285504811, +345349905, +876599880, +476392727, +479589210, +606376325 +}, +{ +174997730, +778177086, +319164313, +163614456, +10331364, +599358958, +8331663, +237538058, +159173957, +174533880, +65588684, +878222844, +424467599, +901803515, +187504218, +776690353 +}, +{ +803856182, +965850321, +694948067, +218315960, +358416571, +683713254, +178069303, +428076035, +686176454, +579553217, +357306738, +315018080, +886852373, +568563910, +896839725, +257416821 +}, +{ +401650013, +183289141, +497957228, +879734476, +265024455, +825794561, +889237440, +323359863, +100258491, +991414783, +313986632, +85847250, +362520248, +276103512, +1041630342, +525981595 +}, +{ +487732740, +46201705, +990837834, +62744493, +1067364756, +58015363, +690846283, +680262648, +997278956, +469357861, +432164624, +996763915, +211907847, +167824295, +144928194, +454839915 +}, +{ +41404232, +514493300, +259546924, +578217256, +972345130, +123299213, +346040332, +1014668104, +520910639, +579955198, +36627803, +179072921, +547684341, +598950511, +269497394, +854352266 +}, +{ +603906768, +100863318, +708837659, +204175569, +375560904, +908375384, +28314106, +6303733, +175283124, +749851198, +308667367, +415293931, +225365403, +1032188331, +977112710, +819705229 +}, +{ +399767123, +697985692, +356790426, +643687584, +298624218, +185095167, +381653926, +876816342, +296720023, +2205879, +235816616, +521850105, +622753786, +1021421218, +726349744, +256504902 +}, +{ +851245024, +1022500222, +511909628, +313809625, +99776025, +39710175, +798739932, +741832408, +140631966, +898295927, +607660421, +870669312, +1051422478, +789055529, +669113756, +681943450 +}, +{ +853872755, +491465269, +503341472, +98019440, +258267420, +335602837, +320687824, +1053324395, +24932389, +955011453, +934255131, +435625663, +501568768, +238967025, +549987406, +248619780 +}, +{ +411151284, +576471205, +757985419, +544137226, +968135693, +877548443, +194586894, +74882373, +248353663, +21207540, +273789651, +853653916, +861267970, +533253322, +3739570, +661358586 +}, +{ +271430986, +71390029, +257643671, +949329860, +348156406, +251939238, +445808698, +48269799, +907589462, +105677619, +635451508, +20805932, +464874661, +7542147, +243619464, +288304568 +}, +{ +368215982, +530288964, +770090421, +660961164, +614935537, +630760399, +931299233, +794519275, +779918979, +401746493, +561237006, +1027202224, +258968003, +339508073, +1050610516, +1064307013 +}, +{ +1039172162, +448331205, +928997884, +49813151, +198712120, +992335354, +671024050, +879525220, +745915336, +1038822580, +138669665, +917958819, +681422342, +792868818, +924762727, +816386174 +}, +{ +515190336, +313808618, +441296783, +1022120897, +792325033, +354387581, +59273006, +280075434, +411357221, +665274694, +4054464, +1059046246, +394261773, +848616745, +15446017, +517723271 +}}; + + +class H3BloomFilter : public AbstractBloomFilter { +public: + + ~H3BloomFilter(); + H3BloomFilter(string config); + + void clear(); + void increment(const Address& addr); + void decrement(const Address& addr); + void merge(AbstractBloomFilter * other_filter); + void set(const Address& addr); + void unset(const Address& addr); + + bool isSet(const Address& addr); + int getCount(const Address& addr); + int getTotalCount(); + void print(ostream& out) const; + + int getIndex(const Address& addr); + int readBit(const int index); + void writeBit(const int index, const int value); + + int operator[](const int index) const{ + return this->m_filter[index]; + } + +private: + + int get_index(const Address& addr, int hashNumber); + + int hash_H3(uint64 value, int index); + + Vector m_filter; + int m_filter_size; + int m_num_hashes; + int m_filter_size_bits; + + int m_par_filter_size; + int m_par_filter_size_bits; + + int m_count_bits; + int m_count; + + + + int primes_list[6];// = {9323,11279,10247,30637,25717,43711}; + int mults_list[6]; //= {255,29,51,3,77,43}; + int adds_list[6]; //= {841,627,1555,241,7777,65391}; + + bool isParallel; + +}; + + +#endif diff --git a/src/mem/ruby/filters/LSB_CountingBloomFilter.cc b/src/mem/ruby/filters/LSB_CountingBloomFilter.cc new file mode 100644 index 000000000..fd2e2653c --- /dev/null +++ b/src/mem/ruby/filters/LSB_CountingBloomFilter.cc @@ -0,0 +1,141 @@ + +/* + * Copyright (c) 1999-2008 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. + */ + +/* + * LSB_CountingBloomFilter.cc + * + * Description: + * + * + */ + +#include "mem/ruby/filters/LSB_CountingBloomFilter.hh" +#include "mem/gems_common/Map.hh" +#include "mem/ruby/common/Address.hh" + +LSB_CountingBloomFilter::LSB_CountingBloomFilter(string str) +{ + string tail(str); + string head = string_split(tail, ':'); + + m_filter_size = atoi(head.c_str()); + m_filter_size_bits = log_int(m_filter_size); + + m_count = atoi(tail.c_str()); + m_count_bits = log_int(m_count); + + m_filter.setSize(m_filter_size); + clear(); +} + +LSB_CountingBloomFilter::~LSB_CountingBloomFilter(){ +} + +void LSB_CountingBloomFilter::clear() +{ + for (int i = 0; i < m_filter_size; i++) { + m_filter[i] = 0; + } +} + +void LSB_CountingBloomFilter::increment(const Address& addr) +{ + int i = get_index(addr); + if (m_filter[i] < m_count); + m_filter[i] += 1; +} + + +void LSB_CountingBloomFilter::decrement(const Address& addr) +{ + int i = get_index(addr); + if (m_filter[i] > 0) + m_filter[i] -= 1; +} + +void LSB_CountingBloomFilter::merge(AbstractBloomFilter * other_filter) +{ + // TODO +} + +void LSB_CountingBloomFilter::set(const Address& addr) +{ + // TODO +} + +void LSB_CountingBloomFilter::unset(const Address& addr) +{ + // TODO +} + +bool LSB_CountingBloomFilter::isSet(const Address& addr) +{ + // TODO +} + + +int LSB_CountingBloomFilter::getCount(const Address& addr) +{ + return m_filter[get_index(addr)]; +} + +int LSB_CountingBloomFilter::getTotalCount() +{ + int count = 0; + + for (int i = 0; i < m_filter_size; i++) { + count += m_filter[i]; + } + return count; +} + +int LSB_CountingBloomFilter::getIndex(const Address& addr) +{ + return get_index(addr); +} + +void LSB_CountingBloomFilter::print(ostream& out) const +{ +} + +int LSB_CountingBloomFilter::readBit(const int index) { + return 0; + // TODO +} + +void LSB_CountingBloomFilter::writeBit(const int index, const int value) { + // TODO +} + +int LSB_CountingBloomFilter::get_index(const Address& addr) +{ + return addr.bitSelect( RubySystem::getBlockSizeBits(), RubySystem::getBlockSizeBits() + m_filter_size_bits - 1); +} + + diff --git a/src/mem/ruby/filters/LSB_CountingBloomFilter.hh b/src/mem/ruby/filters/LSB_CountingBloomFilter.hh new file mode 100644 index 000000000..7a0f71fad --- /dev/null +++ b/src/mem/ruby/filters/LSB_CountingBloomFilter.hh @@ -0,0 +1,82 @@ + +/* + * Copyright (c) 1999-2008 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. + */ + +/* + * LSB_CountingBloomFilter.hh + * + * Description: + * + * + */ + +#ifndef LSB_COUNTING_BLOOM_FILTER_H +#define LSB_COUNTING_BLOOM_FILTER_H + +#include "mem/gems_common/Map.hh" +#include "mem/ruby/common/Global.hh" +#include "mem/ruby/config/RubyConfig.hh" +#include "mem/ruby/common/Address.hh" +#include "mem/ruby/filters/AbstractBloomFilter.hh" + +class LSB_CountingBloomFilter : public AbstractBloomFilter { +public: + + ~LSB_CountingBloomFilter(); + LSB_CountingBloomFilter(string config); + + void clear(); + void increment(const Address& addr); + void decrement(const Address& addr); + void merge(AbstractBloomFilter * other_filter); + void set(const Address& addr); + void unset(const Address& addr); + + bool isSet(const Address& addr); + int getCount(const Address& addr); + int getTotalCount(); + int getIndex(const Address& addr); + int readBit(const int index); + void writeBit(const int index, const int value); + + void print(ostream& out) const; + +private: + + int get_index(const Address& addr); + + Vector m_filter; + int m_filter_size; + int m_filter_size_bits; + + int m_count_bits; + int m_count; +}; + + +#endif diff --git a/src/mem/ruby/filters/MultiBitSelBloomFilter.cc b/src/mem/ruby/filters/MultiBitSelBloomFilter.cc new file mode 100644 index 000000000..844f80160 --- /dev/null +++ b/src/mem/ruby/filters/MultiBitSelBloomFilter.cc @@ -0,0 +1,191 @@ + +/* + * Copyright (c) 1999-2008 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. + */ + +/* + * NonCountingBloomFilter.cc + * + * Description: + * + * + */ + +#include "mem/ruby/filters/MultiBitSelBloomFilter.hh" +#include "mem/gems_common/Map.hh" +#include "mem/ruby/common/Address.hh" + +MultiBitSelBloomFilter::MultiBitSelBloomFilter(string str) +{ + + string tail(str); + string head = string_split(tail, '_'); + + // head contains filter size, tail contains bit offset from block number + m_filter_size = atoi(head.c_str()); + + head = string_split(tail, '_'); + m_num_hashes = atoi(head.c_str()); + + head = string_split(tail, '_'); + m_skip_bits = atoi(head.c_str()); + + if(tail == "Regular") { + isParallel = false; + } else if (tail == "Parallel") { + isParallel = true; + } else { + cout << "ERROR: Incorrect config string for MultiBitSel Bloom! :" << str << endl; + assert(0); + } + + m_filter_size_bits = log_int(m_filter_size); + + m_par_filter_size = m_filter_size/m_num_hashes; + m_par_filter_size_bits = log_int(m_par_filter_size); + + m_filter.setSize(m_filter_size); + clear(); +} + +MultiBitSelBloomFilter::~MultiBitSelBloomFilter(){ +} + +void MultiBitSelBloomFilter::clear() +{ + for (int i = 0; i < m_filter_size; i++) { + m_filter[i] = 0; + } +} + +void MultiBitSelBloomFilter::increment(const Address& addr) +{ + // Not used +} + + +void MultiBitSelBloomFilter::decrement(const Address& addr) +{ + // Not used +} + +void MultiBitSelBloomFilter::merge(AbstractBloomFilter * other_filter){ + // assumes both filters are the same size! + MultiBitSelBloomFilter * temp = (MultiBitSelBloomFilter*) other_filter; + for(int i=0; i < m_filter_size; ++i){ + m_filter[i] |= (*temp)[i]; + } + +} + +void MultiBitSelBloomFilter::set(const Address& addr) +{ + for (int i = 0; i < m_num_hashes; i++) { + int idx = get_index(addr, i); + m_filter[idx] = 1; + + //Profile hash value distribution + //g_system_ptr->getProfiler()->getXactProfiler()->profileHashValue(i, idx); //gem5:Arka for decomissioning of log_tm + } +} + +void MultiBitSelBloomFilter::unset(const Address& addr) +{ + cout << "ERROR: Unset should never be called in a Bloom filter"; + assert(0); +} + +bool MultiBitSelBloomFilter::isSet(const Address& addr) +{ + bool res = true; + + for (int i=0; i < m_num_hashes; i++) { + int idx = get_index(addr, i); + res = res && m_filter[idx]; + } + return res; +} + + +int MultiBitSelBloomFilter::getCount(const Address& addr) +{ + return isSet(addr)? 1: 0; +} + +int MultiBitSelBloomFilter::getIndex(const Address& addr) +{ + return 0; +} + +int MultiBitSelBloomFilter::readBit(const int index) { + return 0; +} + +void MultiBitSelBloomFilter::writeBit(const int index, const int value) { + +} + +int MultiBitSelBloomFilter::getTotalCount() +{ + int count = 0; + + for (int i = 0; i < m_filter_size; i++) { + count += m_filter[i]; + } + return count; +} + +void MultiBitSelBloomFilter::print(ostream& out) const +{ +} + +int MultiBitSelBloomFilter::get_index(const Address& addr, int i) +{ + // m_skip_bits is used to perform BitSelect after skipping some bits. Used to simulate BitSel hashing on larger than cache-line granularities + uint64 x = (addr.getLineAddress()) >> m_skip_bits; + int y = hash_bitsel(x, i, m_num_hashes, 30, m_filter_size_bits); + //36-bit addresses, 6-bit cache lines + + if(isParallel) { + return (y % m_par_filter_size) + i*m_par_filter_size; + } else { + return y % m_filter_size; + } +} + + +int MultiBitSelBloomFilter::hash_bitsel(uint64 value, int index, int jump, int maxBits, int numBits) { + uint64 mask = 1; + int result = 0; + int bit, i; + + for(i = 0; i < numBits; i++) { + bit = (index + jump*i) % maxBits; + if (value & (mask << bit)) result += mask << i; + } + return result; +} diff --git a/src/mem/ruby/filters/MultiBitSelBloomFilter.hh b/src/mem/ruby/filters/MultiBitSelBloomFilter.hh new file mode 100644 index 000000000..390b7c37c --- /dev/null +++ b/src/mem/ruby/filters/MultiBitSelBloomFilter.hh @@ -0,0 +1,97 @@ + +/* + * Copyright (c) 1999-2008 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. + */ + +/* + * MultiBitSelBloomFilter.hh + * + * Description: + * + * + */ + +#ifndef MULTIBITSEL_BLOOM_FILTER_H +#define MULTIBITSEL_BLOOM_FILTER_H + +#include "mem/gems_common/Map.hh" +#include "mem/ruby/common/Global.hh" +#include "mem/ruby/system/System.hh" +#include "mem/ruby/profiler/Profiler.hh" +#include "mem/ruby/config/RubyConfig.hh" +#include "mem/ruby/common/Address.hh" +#include "mem/ruby/filters/AbstractBloomFilter.hh" + +class MultiBitSelBloomFilter : public AbstractBloomFilter { +public: + + ~MultiBitSelBloomFilter(); + MultiBitSelBloomFilter(string config); + + void clear(); + void increment(const Address& addr); + void decrement(const Address& addr); + void merge(AbstractBloomFilter * other_filter); + void set(const Address& addr); + void unset(const Address& addr); + + bool isSet(const Address& addr); + int getCount(const Address& addr); + int getTotalCount(); + void print(ostream& out) const; + + int getIndex(const Address& addr); + int readBit(const int index); + void writeBit(const int index, const int value); + + int operator[](const int index) const{ + return this->m_filter[index]; + } + +private: + + int get_index(const Address& addr, int hashNumber); + + int hash_bitsel(uint64 value, int index, int jump, int maxBits, int numBits); + + Vector m_filter; + int m_filter_size; + int m_num_hashes; + int m_filter_size_bits; + int m_skip_bits; + + int m_par_filter_size; + int m_par_filter_size_bits; + + int m_count_bits; + int m_count; + + bool isParallel; + +}; + +#endif diff --git a/src/mem/ruby/filters/MultiGrainBloomFilter.cc b/src/mem/ruby/filters/MultiGrainBloomFilter.cc new file mode 100644 index 000000000..ff32ce923 --- /dev/null +++ b/src/mem/ruby/filters/MultiGrainBloomFilter.cc @@ -0,0 +1,172 @@ + +/* + * Copyright (c) 1999-2008 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. + */ + +/* + * MultiGrainBloomFilter.cc + * + * Description: + * + * + */ + +#include "mem/ruby/filters/MultiGrainBloomFilter.hh" +#include "mem/gems_common/Map.hh" +#include "mem/ruby/common/Address.hh" + +MultiGrainBloomFilter::MultiGrainBloomFilter(string str) +{ + string tail(str); + + // split into the 2 filter sizes + string head = string_split(tail, '_'); + + // head contains size of 1st bloom filter, tail contains size of 2nd bloom filter + + m_filter_size = atoi(head.c_str()); + m_filter_size_bits = log_int(m_filter_size); + + m_page_filter_size = atoi(tail.c_str()); + m_page_filter_size_bits = log_int(m_page_filter_size); + + m_filter.setSize(m_filter_size); + m_page_filter.setSize(m_page_filter_size); + clear(); +} + +MultiGrainBloomFilter::~MultiGrainBloomFilter(){ +} + +void MultiGrainBloomFilter::clear() +{ + for (int i = 0; i < m_filter_size; i++) { + m_filter[i] = 0; + } + for(int i=0; i < m_page_filter_size; ++i){ + m_page_filter[i] = 0; + } +} + +void MultiGrainBloomFilter::increment(const Address& addr) +{ + // Not used +} + + +void MultiGrainBloomFilter::decrement(const Address& addr) +{ + // Not used +} + +void MultiGrainBloomFilter::merge(AbstractBloomFilter * other_filter) +{ + // TODO +} + +void MultiGrainBloomFilter::set(const Address& addr) +{ + int i = get_block_index(addr); + int j = get_page_index(addr); + assert(i < m_filter_size); + assert(j < m_page_filter_size); + m_filter[i] = 1; + m_page_filter[i] = 1; + +} + +void MultiGrainBloomFilter::unset(const Address& addr) +{ + // not used +} + +bool MultiGrainBloomFilter::isSet(const Address& addr) +{ + int i = get_block_index(addr); + int j = get_page_index(addr); + assert(i < m_filter_size); + assert(j < m_page_filter_size); + // we have to have both indices set + return (m_filter[i] && m_page_filter[i]); +} + +int MultiGrainBloomFilter::getCount(const Address& addr) +{ + // not used + return 0; +} + +int MultiGrainBloomFilter::getTotalCount() +{ + int count = 0; + + for (int i = 0; i < m_filter_size; i++) { + count += m_filter[i]; + } + + for(int i=0; i < m_page_filter_size; ++i){ + count += m_page_filter[i] = 0; + } + + return count; +} + +int MultiGrainBloomFilter::getIndex(const Address& addr) +{ + return 0; + // TODO +} + +int MultiGrainBloomFilter::readBit(const int index) { + return 0; + // TODO +} + +void MultiGrainBloomFilter::writeBit(const int index, const int value) { + // TODO +} + +void MultiGrainBloomFilter::print(ostream& out) const +{ +} + +int MultiGrainBloomFilter::get_block_index(const Address& addr) +{ + // grap a chunk of bits after byte offset + return addr.bitSelect( RubySystem::getBlockSizeBits(), RubySystem::getBlockSizeBits() + m_filter_size_bits - 1); +} + +int MultiGrainBloomFilter::get_page_index(const Address & addr) +{ + // grap a chunk of bits after first chunk + return addr.bitSelect( RubySystem::getBlockSizeBits() + m_filter_size_bits - 1, + RubySystem::getBlockSizeBits() + m_filter_size_bits - 1 + m_page_filter_size_bits - 1); +} + + + + diff --git a/src/mem/ruby/filters/MultiGrainBloomFilter.hh b/src/mem/ruby/filters/MultiGrainBloomFilter.hh new file mode 100644 index 000000000..66a32ecd4 --- /dev/null +++ b/src/mem/ruby/filters/MultiGrainBloomFilter.hh @@ -0,0 +1,88 @@ + +/* + * Copyright (c) 1999-2008 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. + */ + +/* + * MultiGrainBloomFilter.hh + * + * Description: + * + * + */ + +#ifndef MULTIGRAIN_BLOOM_FILTER_H +#define MULTIGRAIN_BLOOM_FILTER_H + +#include "mem/gems_common/Map.hh" +#include "mem/ruby/common/Global.hh" +#include "mem/ruby/config/RubyConfig.hh" +#include "mem/ruby/common/Address.hh" +#include "mem/ruby/filters/AbstractBloomFilter.hh" + +class MultiGrainBloomFilter : public AbstractBloomFilter { +public: + + ~MultiGrainBloomFilter(); + MultiGrainBloomFilter(string str); + + void clear(); + void increment(const Address& addr); + void decrement(const Address& addr); + void merge(AbstractBloomFilter * other_filter); + void set(const Address& addr); + void unset(const Address& addr); + + bool isSet(const Address& addr); + int getCount(const Address& addr); + int getTotalCount(); + int getIndex(const Address& addr); + int readBit(const int index); + void writeBit(const int index, const int value); + + void print(ostream& out) const; + +private: + + int get_block_index(const Address& addr); + int get_page_index(const Address & addr); + + // The block filter + Vector m_filter; + int m_filter_size; + int m_filter_size_bits; + // The page number filter + Vector m_page_filter; + int m_page_filter_size; + int m_page_filter_size_bits; + + int m_count_bits; + int m_count; +}; + + +#endif diff --git a/src/mem/ruby/filters/NonCountingBloomFilter.cc b/src/mem/ruby/filters/NonCountingBloomFilter.cc new file mode 100644 index 000000000..738945105 --- /dev/null +++ b/src/mem/ruby/filters/NonCountingBloomFilter.cc @@ -0,0 +1,144 @@ + +/* + * Copyright (c) 1999-2008 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. + */ + +/* + * NonCountingBloomFilter.cc + * + * Description: + * + * + */ + +#include "mem/ruby/filters/NonCountingBloomFilter.hh" +#include "mem/gems_common/Map.hh" +#include "mem/ruby/common/Address.hh" + +NonCountingBloomFilter::NonCountingBloomFilter(string str) +{ + string tail(str); + string head = string_split(tail, '_'); + + // head contains filter size, tail contains bit offset from block number + m_filter_size = atoi(head.c_str()); + m_offset = atoi(tail.c_str()); + m_filter_size_bits = log_int(m_filter_size); + + + m_filter.setSize(m_filter_size); + clear(); +} + +NonCountingBloomFilter::~NonCountingBloomFilter(){ +} + +void NonCountingBloomFilter::clear() +{ + for (int i = 0; i < m_filter_size; i++) { + m_filter[i] = 0; + } +} + +void NonCountingBloomFilter::increment(const Address& addr) +{ + // Not used +} + + +void NonCountingBloomFilter::decrement(const Address& addr) +{ + // Not used +} + +void NonCountingBloomFilter::merge(AbstractBloomFilter * other_filter){ + // assumes both filters are the same size! + NonCountingBloomFilter * temp = (NonCountingBloomFilter*) other_filter; + for(int i=0; i < m_filter_size; ++i){ + m_filter[i] |= (*temp)[i]; + } + +} + +void NonCountingBloomFilter::set(const Address& addr) +{ + int i = get_index(addr); + m_filter[i] = 1; +} + +void NonCountingBloomFilter::unset(const Address& addr) +{ + int i = get_index(addr); + m_filter[i] = 0; +} + +bool NonCountingBloomFilter::isSet(const Address& addr) +{ + int i = get_index(addr); + return (m_filter[i]); +} + + +int NonCountingBloomFilter::getCount(const Address& addr) +{ + return m_filter[get_index(addr)]; +} + +int NonCountingBloomFilter::getTotalCount() +{ + int count = 0; + + for (int i = 0; i < m_filter_size; i++) { + count += m_filter[i]; + } + return count; +} + +void NonCountingBloomFilter::print(ostream& out) const +{ +} + +int NonCountingBloomFilter::getIndex(const Address& addr) +{ + return get_index(addr); +} + +int NonCountingBloomFilter::readBit(const int index) { + return m_filter[index]; +} + +void NonCountingBloomFilter::writeBit(const int index, const int value) { + m_filter[index] = value; +} + +int NonCountingBloomFilter::get_index(const Address& addr) +{ + return addr.bitSelect( RubySystem::getBlockSizeBits() + m_offset, + RubySystem::getBlockSizeBits() + m_offset + m_filter_size_bits - 1); +} + + diff --git a/src/mem/ruby/filters/NonCountingBloomFilter.hh b/src/mem/ruby/filters/NonCountingBloomFilter.hh new file mode 100644 index 000000000..27045ebc9 --- /dev/null +++ b/src/mem/ruby/filters/NonCountingBloomFilter.hh @@ -0,0 +1,88 @@ + +/* + * Copyright (c) 1999-2008 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. + */ + +/* + * NonCountingBloomFilter.hh + * + * Description: + * + * + */ + +#ifndef NONCOUNTING_BLOOM_FILTER_H +#define NONCOUNTING_BLOOM_FILTER_H + +#include "mem/gems_common/Map.hh" +#include "mem/ruby/common/Global.hh" +#include "mem/ruby/config/RubyConfig.hh" +#include "mem/ruby/common/Address.hh" +#include "mem/ruby/filters/AbstractBloomFilter.hh" + +class NonCountingBloomFilter : public AbstractBloomFilter { +public: + + ~NonCountingBloomFilter(); + NonCountingBloomFilter(string config); + + void clear(); + void increment(const Address& addr); + void decrement(const Address& addr); + void merge(AbstractBloomFilter * other_filter); + void set(const Address& addr); + void unset(const Address& addr); + + bool isSet(const Address& addr); + int getCount(const Address& addr); + int getTotalCount(); + + int getIndex(const Address& addr); + int readBit(const int index); + void writeBit(const int index, const int value); + + void print(ostream& out) const; + + int operator[](const int index) const{ + return this->m_filter[index]; + } + +private: + + int get_index(const Address& addr); + + Vector m_filter; + int m_filter_size; + int m_offset; + int m_filter_size_bits; + + int m_count_bits; + int m_count; +}; + + +#endif diff --git a/src/mem/ruby/init.cc b/src/mem/ruby/init.cc deleted file mode 100644 index a4aefaad3..000000000 --- a/src/mem/ruby/init.cc +++ /dev/null @@ -1,191 +0,0 @@ - -/* - * Copyright (c) 1999-2008 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. - */ - -/* - * init.C - * - * Description: See init.hh - * - * $Id$ - * - */ - -#include "mem/ruby/common/Global.hh" -#include "mem/ruby/eventqueue/RubyEventQueue.hh" -#include "mem/ruby/system/System.hh" -#include "mem/ruby/common/Debug.hh" -#include "mem/ruby/common/Driver.hh" -#include "mem/ruby/profiler/Profiler.hh" -#include "mem/ruby/tester/Tester.hh" -#include "mem/ruby/init.hh" - -using namespace std; -#include -#include -#include - -#include "mem/gems_common/ioutil/confio.hh" -#include "mem/gems_common/ioutil/initvar.hh" - -// A generated file containing the default parameters in string form -// The defaults are stored in the variable global_default_param -#include "mem/ruby/default_param.hh" - -static initvar_t *ruby_initvar_obj = NULL; - -//*************************************************************************** -static void init_generate_values( void ) -{ - /* update generated values, based on input configuration */ -} - -//*************************************************************************** - -void init_variables( void ) -{ - // allocate the "variable initialization" package - ruby_initvar_obj = new initvar_t( "ruby", "../../../ruby/", - global_default_param, - &init_simulator, - &init_generate_values); -} - - - /* -void init_variables(const char* config_str ) -{ - // allocate the "variable initialization" package - ruby_initvar_obj = new initvar_t( "ruby", "../../../ruby/", - config_str, - &init_simulator, - &init_generate_values ); -} - */ - -void init_simulator() -{ - // Set things to NULL to make sure we don't de-reference them - // without a seg. fault. - g_system_ptr = NULL; - g_debug_ptr = NULL; - g_eventQueue_ptr = NULL; - - cout << "Ruby Timing Mode" << endl; - - - g_debug_ptr = new Debug( DEBUG_FILTER_STRING, - DEBUG_VERBOSITY_STRING, - DEBUG_START_TIME, - DEBUG_OUTPUT_FILENAME ); - RubyConfig::init(); - - cout << "Creating event queue..." << endl; - g_eventQueue_ptr = new RubyEventQueue; - cout << "Creating event queue done" << endl; - - cout << "Creating system..." << endl; - cout << " Processors: " << RubyConfig::numberOfProcessors() << endl; - - g_system_ptr = new RubySystem; - cout << "Creating system done" << endl; - - cout << "Ruby initialization complete" << endl; -} - -void init_simulator(Driver* _driver) -{ - // Set things to NULL to make sure we don't de-reference them - // without a seg. fault. - g_system_ptr = NULL; - g_debug_ptr = NULL; - g_eventQueue_ptr = NULL; - - cout << "Ruby Timing Mode" << endl; - - - g_debug_ptr = new Debug( DEBUG_FILTER_STRING, - DEBUG_VERBOSITY_STRING, - DEBUG_START_TIME, - DEBUG_OUTPUT_FILENAME ); - RubyConfig::init(); - - cout << "Creating event queue..." << endl; - g_eventQueue_ptr = new RubyEventQueue; - cout << "Creating event queue done" << endl; - - cout << "Creating system..." << endl; - cout << " Processors: " << RubyConfig::numberOfProcessors() << endl; - - g_system_ptr = new RubySystem(_driver); - cout << "Creating system done" << endl; - - cout << "Ruby initialization complete" << endl; -} - -void destroy_simulator() -{ - cout << "Deleting system..." << endl; - delete g_system_ptr; - cout << "Deleting system done" << endl; - - cout << "Deleting event queue..." << endl; - delete g_eventQueue_ptr; - cout << "Deleting event queue done" << endl; - - delete g_debug_ptr; -} - -/*-------------------------------------------------------------------------+ - | DG: These are the external load and unload hooks that will be called by | - | M5 in phase 1 integration, and possibly afterwards, too. | - +-------------------------------------------------------------------------*/ - -//dsm: superfluous -/*extern "C" -int OnLoadRuby() { - init_variables(); - return 0; -} - -extern "C" -int OnInitRuby() { - init_simulator(); - return 0; -} - -extern "C" -int OnUnloadRuby() { - destroy_simulator(); - return 0; -}*/ - -/* I have to put it somewhere for now */ -void tester_main(int argc, char **argv) { - std::cout << __FILE__ << "(" << __LINE__ << "): Not implemented." << std::endl; -} diff --git a/src/mem/ruby/init.hh b/src/mem/ruby/init.hh deleted file mode 100644 index 35af0e603..000000000 --- a/src/mem/ruby/init.hh +++ /dev/null @@ -1,50 +0,0 @@ - -/* - * Copyright (c) 1999-2008 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. - */ - -/* - * init.hh - * - * Description: - * - * $Id$ - * - */ - -#ifndef INIT_H -#define INIT_H - -class Driver; - -extern void init_variables(); -//extern void init_variables(const char* config_str); -extern void init_simulator(); -extern void init_simulator(Driver* _driver); -extern void destroy_simulator(); - -#endif //INIT_H diff --git a/src/mem/ruby/libruby.cc b/src/mem/ruby/libruby.cc new file mode 100644 index 000000000..4083a888c --- /dev/null +++ b/src/mem/ruby/libruby.cc @@ -0,0 +1,206 @@ + +#include +#include + +#include "mem/ruby/libruby_internal.hh" +#include "mem/ruby/system/RubyPort.hh" +#include "mem/ruby/system/System.hh" +#include "mem/ruby/eventqueue/RubyEventQueue.hh" +#include "mem/ruby/system/MemoryVector.hh" +#include "mem/ruby/common/Address.hh" + +string RubyRequestType_to_string(const RubyRequestType& obj) +{ + switch(obj) { + case RubyRequestType_IFETCH: + return "IFETCH"; + case RubyRequestType_LD: + return "LD"; + case RubyRequestType_ST: + return "ST"; + case RubyRequestType_RMW: + return "RMW"; + case RubyRequestType_NULL: + default: + assert(0); + return ""; + } +} + +RubyRequestType string_to_RubyRequestType(std::string str) +{ + if (str == "IFETCH") + return RubyRequestType_IFETCH; + else if (str == "LD") + return RubyRequestType_LD; + else if (str == "ST") + return RubyRequestType_ST; + else if (str == "RMW") + return RubyRequestType_RMW; + else + assert(0); + return RubyRequestType_NULL; +} + +ostream& operator<<(ostream& out, const RubyRequestType& obj) +{ + cerr << "in op" << endl; + out << RubyRequestType_to_string(obj); + cerr << "flushing" << endl; + out << flush; + cerr << "done" << endl; + return out; +} + +vector tokenizeString(string str, string delims) +{ + vector tokens; + char* pch; + char* tmp; + const char* c_delims = delims.c_str(); + tmp = new char[str.length()+1]; + strcpy(tmp, str.c_str()); + pch = strtok(tmp, c_delims); + while (pch != NULL) { + string tmp_str(pch); + if (tmp_str == "null") tmp_str = ""; + tokens.push_back(tmp_str); + + pch = strtok(NULL, c_delims); + } + delete [] tmp; + return tokens; +} + +void libruby_init(const char* cfg_filename) +{ + stringstream cfg_output; + + // first we execute the Ruby-lang configuration script + int fd[2]; + int pid; + if (pipe(fd) == -1) { + perror("Error Creating Pipe"); + exit(EXIT_FAILURE); + } + + pid = fork(); + if (pid == -1){ + perror("Error forking"); + exit(EXIT_FAILURE); + } + + if (!pid) { + // child + close(fd[0]); // close the read end of the pipe + // replace stdout with the write pipe + if (dup2(fd[1], STDOUT_FILENO) == -1) { + perror("Error redirecting stdout"); + exit(EXIT_FAILURE); + } +#define QUOTE_MACRO(x, y) QUOTE_TXT(x,y) +#define QUOTE_TXT(x, y) #x y + if (execlp("ruby", "ruby", "-I", QUOTE_MACRO(GEMS_ROOT, "/ruby/config"), QUOTE_MACRO(GEMS_ROOT, "/ruby/config/print_cfg.rb"), "-r", cfg_filename, NULL)) { + perror("execlp"); + exit(EXIT_FAILURE); + } + } else { + close(fd[1]); + + int child_status; + if (wait(&child_status) == -1) { + perror("wait"); + exit(EXIT_FAILURE); + } + if (child_status != EXIT_SUCCESS) { + exit(EXIT_FAILURE); + } + + char buf[100]; + int bytes_read; + while( (bytes_read = read(fd[0], buf, 100)) > 0 ) { + for (int i=0;i * sys_conf = new vector; + + string line; + getline(cfg_output, line) ; + while ( !cfg_output.eof() ) { + vector tokens = tokenizeString(line, " "); + assert(tokens.size() >= 2); + vector argv; + for (size_t i=2; ipush_back(RubyObjConf(tokens[0], tokens[1], argv)); + tokens.clear(); + argv.clear(); + getline(cfg_output, line); + } + + RubySystem::create(*sys_conf); + delete sys_conf; +} + +RubyPortHandle libruby_get_port(const char* port_name, void (*hit_callback)(int64_t access_id)) +{ + return static_cast(RubySystem::getPort(port_name, hit_callback)); +} + +RubyPortHandle libruby_get_port_by_name(const char* port_name) +{ + return static_cast(RubySystem::getPortOnly(port_name)); +} + +void libruby_write_ram(uint64_t paddr, uint8_t* data, int len) +{ + RubySystem::getMemoryVector()->write(Address(paddr), data, len); +} + +void libruby_read_ram(uint64_t paddr, uint8_t* data, int len) +{ + RubySystem::getMemoryVector()->read(Address(paddr), data, len); +} + +int64_t libruby_issue_request(RubyPortHandle p, struct RubyRequest request) +{ + return static_cast(p)->makeRequest(request); +} + +int libruby_tick(int n) +{ + RubySystem::getEventQueue()->triggerEvents(RubySystem::getEventQueue()->getTime() + n); + return 0; +} + +void libruby_destroy() +{ +} + +const char* libruby_last_error() +{ + return ""; +} + +void libruby_print_config(std::ostream & out) +{ + RubySystem::printConfig(out); +} + +void libruby_print_stats(std::ostream & out) +{ + RubySystem::printStats(out); +} + +uint64_t libruby_get_time() { + return RubySystem::getCycleCount(0); +} diff --git a/src/mem/ruby/libruby.hh b/src/mem/ruby/libruby.hh new file mode 100644 index 000000000..5916c98e6 --- /dev/null +++ b/src/mem/ruby/libruby.hh @@ -0,0 +1,109 @@ + +#ifndef LIBRUBY_H +#define LIBRUBY_H + +#include +#include + +typedef void* RubyPortHandle; +enum RubyRequestType { + RubyRequestType_NULL, + RubyRequestType_IFETCH, + RubyRequestType_LD, + RubyRequestType_ST, + RubyRequestType_RMW +}; + +enum RubyAccessMode { + RubyAccessMode_User, + RubyAccessMode_Supervisor, + RubyAccessMode_Device +}; + +struct RubyRequest { + uint64_t paddr; + uint8_t* data; + int len; + uint64_t pc; + RubyRequestType type; + RubyAccessMode access_mode; + + RubyRequest() {} + RubyRequest(uint64_t _paddr, uint8_t* _data, int _len, uint64_t _pc, RubyRequestType _type, RubyAccessMode _access_mode) + : paddr(_paddr), data(_data), len(_len), pc(_pc), type(_type), access_mode(_access_mode) + {} +}; + +/** + * Initialize the system. cfg_file is a Ruby-lang configuration script + */ +void libruby_init(const char* cfg_file); + +/** + * Tear down a configured system. Must be invoked after a call to libruby_init. + */ +void libruby_destroy(); + +/** + * Print the last error encountered by ruby. Currently unimplemented. + */ +const char* libruby_last_error(); + +/** + * Retrieve a handle to a RubyPort object, identified by name in the + * configuration. You also pass in the callback function you want + * this port to use when a request completes. Only one handle to a + * port is allowed at a time. + */ +RubyPortHandle libruby_get_port(const char* name, void (*hit_callback)(int64_t access_id)); + +/** + * Retrieve a handle to a RubyPort object, identified by name in the + * configuration. + */ +RubyPortHandle libruby_get_port_by_name(const char* name); + + +/** + * issue_request returns a unique access_id to identify the ruby + * transaction. This access_id is later returned to the caller via + * hit_callback (passed to libruby_get_port) + */ +int64_t libruby_issue_request(RubyPortHandle p, struct RubyRequest request); + +/** + * writes data directly into Ruby's data array. Note that this + * ignores caches, and should be considered incoherent after + * simulation starts. + */ +void libruby_write_ram(uint64_t paddr, uint8_t * data, int len); + +/** + * reads data directory from Ruby's data array. Note that this + * ignores caches, and should be considered incoherent after + * simulation starts + */ +void libruby_read_ram(uint64_t paddr, uint8_t * data, int len); + +/** + * tick the system n cycles. Eventually, will return the number of + * cycles until the next event, but for now it always returns 0 + */ +int libruby_tick(int n); + +/** + * self explainitory + */ +void libruby_print_config(std::ostream & out); + +/** + * self explainitory + */ +void libruby_print_stats(std::ostream & out); + + +/** + * get time + */ +uint64_t libruby_get_time(); +#endif diff --git a/src/mem/ruby/libruby_internal.hh b/src/mem/ruby/libruby_internal.hh new file mode 100644 index 000000000..efa855c82 --- /dev/null +++ b/src/mem/ruby/libruby_internal.hh @@ -0,0 +1,13 @@ +#ifndef LIBRUBY_INTERNAL_H +#define LIBRUBY_INTERNAL_H + +#include "mem/ruby/libruby.hh" + +#include +#include + +std::string RubyRequestType_to_string(const RubyRequestType& obj); +RubyRequestType string_to_RubyRequestType(std::string); +std::ostream& operator<<(std::ostream& out, const RubyRequestType& obj); + +#endif diff --git a/src/mem/ruby/network/Network.cc b/src/mem/ruby/network/Network.cc new file mode 100644 index 000000000..cb3507471 --- /dev/null +++ b/src/mem/ruby/network/Network.cc @@ -0,0 +1,34 @@ + +#include "mem/protocol/MachineType.hh" +#include "mem/ruby/network/Network.hh" + +Network::Network(const string & name) + : m_name(name) +{ + m_virtual_networks = 0; + m_topology_ptr = NULL; +} + +void Network::init(const vector & argv) +{ + m_nodes = MachineType_base_number(MachineType_NUM); // Total nodes in network + + for (size_t i=0; i & argv); // Destructor virtual ~Network() {} // Public Methods - - static Network* createNetwork(int nodes); + int getBufferSize() { return m_buffer_size; } + int getNumberOfVirtualNetworks() { return m_virtual_networks; } + int getEndpointBandwidth() { return m_endpoint_bandwidth; } + bool getAdaptiveRouting() {return m_adaptive_routing; } + int getLinkLatency() { return m_link_latency; } // returns the queue requested for the given component virtual MessageBuffer* getToNetQueue(NodeID id, bool ordered, int netNumber) = 0; @@ -84,7 +91,7 @@ public: virtual void printConfig(ostream& out) const = 0; virtual void print(ostream& out) const = 0; -private: +protected: // Private Methods // Private copy constructor and assignment operator @@ -92,6 +99,15 @@ private: Network& operator=(const Network& obj); // Data Members (m_ prefix) +protected: + const string m_name; + int m_nodes; + int m_virtual_networks; + int m_buffer_size; + int m_endpoint_bandwidth; + Topology* m_topology_ptr; + bool m_adaptive_routing; + int m_link_latency; }; // Output operator declaration @@ -110,7 +126,7 @@ ostream& operator<<(ostream& out, const Network& obj) // Code to map network message size types to an integer number of bytes const int CONTROL_MESSAGE_SIZE = 8; -const int DATA_MESSAGE_SIZE = (64+8); +const int DATA_MESSAGE_SIZE = (RubySystem::getBlockSizeBytes()+8); extern inline int MessageSizeType_to_int(MessageSizeType size_type) diff --git a/src/mem/ruby/network/garnet-fixed-pipeline/CreditLink_d.hh b/src/mem/ruby/network/garnet-fixed-pipeline/CreditLink_d.hh index 5e68198cc..387ed0bc1 100644 --- a/src/mem/ruby/network/garnet-fixed-pipeline/CreditLink_d.hh +++ b/src/mem/ruby/network/garnet-fixed-pipeline/CreditLink_d.hh @@ -11,7 +11,7 @@ class CreditLink_d : public NetworkLink_d { public: - CreditLink_d(int id):NetworkLink_d(id) {} + CreditLink_d(int id, int link_latency, GarnetNetwork_d *net_ptr):NetworkLink_d(id, link_latency, net_ptr) {} }; #endif diff --git a/src/mem/ruby/network/garnet-fixed-pipeline/GarnetNetwork_d.cc b/src/mem/ruby/network/garnet-fixed-pipeline/GarnetNetwork_d.cc index 988b634ce..51393b576 100644 --- a/src/mem/ruby/network/garnet-fixed-pipeline/GarnetNetwork_d.cc +++ b/src/mem/ruby/network/garnet-fixed-pipeline/GarnetNetwork_d.cc @@ -43,10 +43,19 @@ #include "mem/ruby/network/garnet-fixed-pipeline/CreditLink_d.hh" #include "mem/ruby/common/NetDest.hh" -GarnetNetwork_d::GarnetNetwork_d(int nodes) +GarnetNetwork_d::GarnetNetwork_d(const string & name) + : Network(name) { - m_nodes = MachineType_base_number(MachineType_NUM); // Total nodes in network - m_virtual_networks = NUMBER_OF_VIRTUAL_NETWORKS; // Number of virtual networks = number of message classes in the coherence protocol +} + +void GarnetNetwork_d::init(const vector & argv) +{ + Network::init(argv); + + //added by SS + m_network_config_ptr = new NetworkConfig; + m_network_config_ptr->init(argv); + m_ruby_start = 0; m_flits_recieved = 0; m_flits_injected = 0; @@ -80,7 +89,7 @@ GarnetNetwork_d::GarnetNetwork_d(int nodes) } // Setup the network switches - m_topology_ptr = new Topology(this, m_nodes); + m_topology_ptr->makeTopology(); int number_of_routers = m_topology_ptr->numSwitches(); for (int i=0; i average_vc_load; - average_vc_load.setSize(m_virtual_networks*NetworkConfig::getVCsPerClass()); + average_vc_load.setSize(m_virtual_networks*m_network_config_ptr->getVCsPerClass()); - for(int i = 0; i < m_virtual_networks*NetworkConfig::getVCsPerClass(); i++) + for(int i = 0; i < m_virtual_networks*m_network_config_ptr->getVCsPerClass(); i++) { average_vc_load[i] = 0; } @@ -259,7 +268,7 @@ void GarnetNetwork_d::printStats(ostream& out) const Vector vc_load = m_link_ptr_vector[i]->getVcLoad(); for(int j = 0; j < vc_load.size(); j++) { - assert(vc_load.size() == NetworkConfig::getVCsPerClass()*m_virtual_networks); + assert(vc_load.size() == m_network_config_ptr->getVCsPerClass()*m_virtual_networks); average_vc_load[j] += vc_load[j]; } } @@ -267,7 +276,7 @@ void GarnetNetwork_d::printStats(ostream& out) const out << "Average Link Utilization :: " << average_link_utilization << " flits/cycle" << endl; out << "-------------" << endl; - for(int i = 0; i < NetworkConfig::getVCsPerClass()*NUMBER_OF_VIRTUAL_NETWORKS; i++) + for(int i = 0; i < m_network_config_ptr->getVCsPerClass()*m_virtual_networks; i++) { average_vc_load[i] = (double(average_vc_load[i]) / (double(g_eventQueue_ptr->getTime()) - m_ruby_start)); out << "Average VC Load [" << i << "] = " << average_vc_load[i] << " flits/cycle " << endl; @@ -304,7 +313,7 @@ void GarnetNetwork_d::printConfig(ostream& out) const out << "Network Configuration" << endl; out << "---------------------" << endl; out << "network: GarnetNetwork_d" << endl; - out << "topology: " << g_NETWORK_TOPOLOGY << endl; + out << "topology: " << m_topology_ptr->getName() << endl; out << endl; for (int i = 0; i < m_virtual_networks; i++) @@ -337,10 +346,7 @@ void GarnetNetwork_d::printConfig(ostream& out) const { m_router_ptr_vector[i]->printConfig(out); } - if (g_PRINT_TOPOLOGY) - { - m_topology_ptr->printConfig(out); - } + m_topology_ptr->printConfig(out); } void GarnetNetwork_d::print(ostream& out) const diff --git a/src/mem/ruby/network/garnet-fixed-pipeline/GarnetNetwork_d.hh b/src/mem/ruby/network/garnet-fixed-pipeline/GarnetNetwork_d.hh index e0f7aebd9..f4b809443 100644 --- a/src/mem/ruby/network/garnet-fixed-pipeline/GarnetNetwork_d.hh +++ b/src/mem/ruby/network/garnet-fixed-pipeline/GarnetNetwork_d.hh @@ -51,10 +51,15 @@ class CreditLink_d; class GarnetNetwork_d : public Network{ public: - GarnetNetwork_d(int nodes); + GarnetNetwork_d(const string & name); ~GarnetNetwork_d(); + void init(const vector & argv); + + //added by SS + NetworkConfig* getNetworkConfig() { return m_network_config_ptr; } + int getNumNodes(){ return m_nodes;} // returns the queue requested for the given component @@ -99,6 +104,8 @@ public: void makeInternalLink(SwitchID src, NodeID dest, const NetDest& routing_table_entry, int link_latency, int link_weight, int bw_multiplier, bool isReconfiguration); private: + NetworkConfig* m_network_config_ptr; + void checkNetworkAllocation(NodeID id, bool ordered, int network_num); // Private copy constructor and assignment operator @@ -106,8 +113,8 @@ private: GarnetNetwork_d& operator=(const GarnetNetwork_d& obj); /***********Data Members*************/ - int m_virtual_networks; - int m_nodes; +// int m_virtual_networks; +// int m_nodes; int m_flits_recieved, m_flits_injected; double m_network_latency, m_queueing_latency; @@ -122,7 +129,7 @@ private: Vector m_creditlink_ptr_vector; // All links in the network Vector m_ni_ptr_vector; // All NI's in Network - Topology* m_topology_ptr; +// Topology* m_topology_ptr; Time m_ruby_start; }; diff --git a/src/mem/ruby/network/garnet-fixed-pipeline/NetworkInterface_d.cc b/src/mem/ruby/network/garnet-fixed-pipeline/NetworkInterface_d.cc index 77857b1f8..f75997757 100644 --- a/src/mem/ruby/network/garnet-fixed-pipeline/NetworkInterface_d.cc +++ b/src/mem/ruby/network/garnet-fixed-pipeline/NetworkInterface_d.cc @@ -43,7 +43,7 @@ NetworkInterface_d::NetworkInterface_d(int id, int virtual_networks, GarnetNetwo m_id = id; m_net_ptr = network_ptr; m_virtual_networks = virtual_networks; - m_vc_per_vnet = NetworkConfig::getVCsPerClass(); + m_vc_per_vnet = m_net_ptr->getNetworkConfig()->getVCsPerClass(); m_num_vcs = m_vc_per_vnet*m_virtual_networks; m_vc_round_robin = 0; @@ -66,7 +66,7 @@ NetworkInterface_d::NetworkInterface_d(int id, int virtual_networks, GarnetNetwo for(int i = 0; i < m_num_vcs; i++) { - m_out_vc_state.insertAtBottom(new OutVcState_d(i)); + m_out_vc_state.insertAtBottom(new OutVcState_d(i, m_net_ptr)); m_out_vc_state[i]->setState(IDLE_, g_eventQueue_ptr->getTime()); } } @@ -114,7 +114,7 @@ bool NetworkInterface_d::flitisizeMessage(MsgPtr msg_ptr, int vnet) NetDest net_msg_dest = net_msg_ptr->getInternalDestination(); Vector dest_nodes = net_msg_dest.getAllDest(); // gets all the destinations associated with this message. - int num_flits = (int) ceil((double) MessageSizeType_to_int(net_msg_ptr->getMessageSize())/NetworkConfig::getFlitSize() ); // Number of flits is dependent on the link bandwidth available. This is expressed in terms of bytes/cycle or the flit size + int num_flits = (int) ceil((double) MessageSizeType_to_int(net_msg_ptr->getMessageSize())/m_net_ptr->getNetworkConfig()->getFlitSize() ); // Number of flits is dependent on the link bandwidth available. This is expressed in terms of bytes/cycle or the flit size for(int ctr = 0; ctr < dest_nodes.size(); ctr++) // loop because we will be converting all multicast messages into unicast messages { @@ -221,7 +221,7 @@ void NetworkInterface_d::wakeup() if(t_flit->get_type() == TAIL_ || t_flit->get_type() == HEAD_TAIL_) { free_signal = true; - if(!NetworkConfig::isNetworkTesting()) // When we are doing network only testing, the messages do not have to be buffered into the message buffers + if(!m_net_ptr->getNetworkConfig()->isNetworkTesting()) // When we are doing network only testing, the messages do not have to be buffered into the message buffers { outNode_ptr[t_flit->get_vnet()]->enqueue(t_flit->get_msg_ptr(), 1); // enqueueing for protocol buffer. This is not required when doing network only testing } @@ -307,7 +307,7 @@ void NetworkInterface_d::scheduleOutputLink() int NetworkInterface_d::get_vnet(int vc) { - for(int i = 0; i < NUMBER_OF_VIRTUAL_NETWORKS; i++) + for(int i = 0; i < m_net_ptr->getNumberOfVirtualNetworks(); i++) { if(vc >= (i*m_vc_per_vnet) && vc < ((i+1)*m_vc_per_vnet)) { diff --git a/src/mem/ruby/network/garnet-fixed-pipeline/NetworkLink_d.cc b/src/mem/ruby/network/garnet-fixed-pipeline/NetworkLink_d.cc index 94f721646..8382d331f 100644 --- a/src/mem/ruby/network/garnet-fixed-pipeline/NetworkLink_d.cc +++ b/src/mem/ruby/network/garnet-fixed-pipeline/NetworkLink_d.cc @@ -37,6 +37,7 @@ #include "mem/ruby/network/garnet-flexible-pipeline/NetworkConfig.hh" #include "mem/ruby/network/garnet-fixed-pipeline/GarnetNetwork_d.hh" +/* NetworkLink_d::NetworkLink_d(int id) { m_id = id; @@ -45,12 +46,12 @@ NetworkLink_d::NetworkLink_d(int id) linkBuffer = new flitBuffer_d(); m_link_utilized = 0; - m_vc_load.setSize(NetworkConfig::getVCsPerClass()*NUMBER_OF_VIRTUAL_NETWORKS); + m_vc_load.setSize(NetworkConfig::getVCsPerClass()*RubySystem::getNetwork()->getNumberOfVirtualNetworks()); - for(int i = 0; i < NetworkConfig::getVCsPerClass()*NUMBER_OF_VIRTUAL_NETWORKS; i++) + for(int i = 0; i < NetworkConfig::getVCsPerClass()*RubySystem::getNetwork()->getNumberOfVirtualNetworks(); i++) m_vc_load[i] = 0; } - +*/ NetworkLink_d::NetworkLink_d(int id, int link_latency, GarnetNetwork_d *net_ptr) { m_net_ptr = net_ptr; @@ -58,9 +59,9 @@ NetworkLink_d::NetworkLink_d(int id, int link_latency, GarnetNetwork_d *net_ptr) m_latency = link_latency; linkBuffer = new flitBuffer_d(); m_link_utilized = 0; - m_vc_load.setSize(NetworkConfig::getVCsPerClass()*NUMBER_OF_VIRTUAL_NETWORKS); + m_vc_load.setSize(m_net_ptr->getNetworkConfig()->getVCsPerClass()*net_ptr->getNumberOfVirtualNetworks()); - for(int i = 0; i < NetworkConfig::getVCsPerClass()*NUMBER_OF_VIRTUAL_NETWORKS; i++) + for(int i = 0; i < m_net_ptr->getNetworkConfig()->getVCsPerClass()*net_ptr->getNumberOfVirtualNetworks(); i++) m_vc_load[i] = 0; } diff --git a/src/mem/ruby/network/garnet-fixed-pipeline/NetworkLink_d.hh b/src/mem/ruby/network/garnet-fixed-pipeline/NetworkLink_d.hh index 1e81a565b..90fb9f6dc 100644 --- a/src/mem/ruby/network/garnet-fixed-pipeline/NetworkLink_d.hh +++ b/src/mem/ruby/network/garnet-fixed-pipeline/NetworkLink_d.hh @@ -46,7 +46,7 @@ class GarnetNetwork_d; class NetworkLink_d : public Consumer { public: - NetworkLink_d(int id); + //NetworkLink_d(int id); ~NetworkLink_d(); NetworkLink_d(int id, int link_latency, GarnetNetwork_d *net_ptr); diff --git a/src/mem/ruby/network/garnet-fixed-pipeline/OutVcState_d.cc b/src/mem/ruby/network/garnet-fixed-pipeline/OutVcState_d.cc index 4fd040099..69e3ae377 100644 --- a/src/mem/ruby/network/garnet-fixed-pipeline/OutVcState_d.cc +++ b/src/mem/ruby/network/garnet-fixed-pipeline/OutVcState_d.cc @@ -27,7 +27,7 @@ */ /* - * OutVCState_d.C + * OutVCState_d.cc * * Niket Agarwal, Princeton University * @@ -37,10 +37,11 @@ #include "mem/ruby/network/garnet-flexible-pipeline/NetworkConfig.hh" #include "mem/ruby/eventqueue/RubyEventQueue.hh" -OutVcState_d::OutVcState_d(int id) +OutVcState_d::OutVcState_d(int id, GarnetNetwork_d *network_ptr) { + m_network_ptr = network_ptr; m_id = id; m_vc_state = IDLE_; m_time = g_eventQueue_ptr->getTime(); - m_credit_count = NetworkConfig::getBufferSize(); + m_credit_count = m_network_ptr->getNetworkConfig()->getBufferSize(); } diff --git a/src/mem/ruby/network/garnet-fixed-pipeline/OutVcState_d.hh b/src/mem/ruby/network/garnet-fixed-pipeline/OutVcState_d.hh index 959a3d643..dc64b8504 100644 --- a/src/mem/ruby/network/garnet-fixed-pipeline/OutVcState_d.hh +++ b/src/mem/ruby/network/garnet-fixed-pipeline/OutVcState_d.hh @@ -37,10 +37,11 @@ #define OUT_VC_STATE_D_H #include "mem/ruby/network/garnet-fixed-pipeline/NetworkHeader.hh" +#include "mem/ruby/network/garnet-fixed-pipeline/GarnetNetwork_d.hh" class OutVcState_d { public: - OutVcState_d(int id); + OutVcState_d(int id, GarnetNetwork_d *network_ptr); int get_inport() {return m_in_port; } int get_invc() { return m_in_vc; } @@ -75,6 +76,7 @@ public: } private: + GarnetNetwork_d *m_network_ptr; int m_id ; Time m_time; VC_state_type m_vc_state; diff --git a/src/mem/ruby/network/garnet-fixed-pipeline/OutputUnit_d.cc b/src/mem/ruby/network/garnet-fixed-pipeline/OutputUnit_d.cc index 1b8b8097b..eb2450897 100644 --- a/src/mem/ruby/network/garnet-fixed-pipeline/OutputUnit_d.cc +++ b/src/mem/ruby/network/garnet-fixed-pipeline/OutputUnit_d.cc @@ -27,7 +27,7 @@ */ /* - * OutputUnit_d.C + * OutputUnit_d.cc * * Niket Agarwal, Princeton University * @@ -46,7 +46,7 @@ OutputUnit_d::OutputUnit_d(int id, Router_d *router) for(int i = 0; i < m_num_vcs; i++) { - m_outvc_state.insertAtBottom(new OutVcState_d(i)); + m_outvc_state.insertAtBottom(new OutVcState_d(i, m_router->get_net_ptr())); } } diff --git a/src/mem/ruby/network/garnet-fixed-pipeline/Router_d.cc b/src/mem/ruby/network/garnet-fixed-pipeline/Router_d.cc index c59805b48..161e6ecff 100644 --- a/src/mem/ruby/network/garnet-fixed-pipeline/Router_d.cc +++ b/src/mem/ruby/network/garnet-fixed-pipeline/Router_d.cc @@ -48,10 +48,10 @@ Router_d::Router_d(int id, GarnetNetwork_d *network_ptr) { m_id = id; m_network_ptr = network_ptr; - m_virtual_networks = NUMBER_OF_VIRTUAL_NETWORKS; - m_vc_per_vnet = NetworkConfig::getVCsPerClass(); + m_virtual_networks = network_ptr->getNumberOfVirtualNetworks(); + m_vc_per_vnet = m_network_ptr->getNetworkConfig()->getVCsPerClass(); m_num_vcs = m_virtual_networks*m_vc_per_vnet; - m_flit_width = NetworkConfig::getFlitSize(); + m_flit_width = m_network_ptr->getNetworkConfig()->getFlitSize(); m_routing_unit = new RoutingUnit_d(this); m_vc_alloc = new VCallocator_d(this); diff --git a/src/mem/ruby/network/garnet-fixed-pipeline/SWallocator_d.cc b/src/mem/ruby/network/garnet-fixed-pipeline/SWallocator_d.cc index 7ca74244e..dd0378305 100644 --- a/src/mem/ruby/network/garnet-fixed-pipeline/SWallocator_d.cc +++ b/src/mem/ruby/network/garnet-fixed-pipeline/SWallocator_d.cc @@ -207,7 +207,7 @@ void SWallocator_d::check_for_wakeup() int SWallocator_d::get_vnet(int invc) { - for(int i = 0; i < NUMBER_OF_VIRTUAL_NETWORKS; i++) + for(int i = 0; i < RubySystem::getNetwork()->getNumberOfVirtualNetworks(); i++) { if(invc >= (i*m_vc_per_vnet) && invc < ((i+1)*m_vc_per_vnet)) { diff --git a/src/mem/ruby/network/garnet-fixed-pipeline/VCallocator_d.cc b/src/mem/ruby/network/garnet-fixed-pipeline/VCallocator_d.cc index 6f13ba14f..810aea175 100644 --- a/src/mem/ruby/network/garnet-fixed-pipeline/VCallocator_d.cc +++ b/src/mem/ruby/network/garnet-fixed-pipeline/VCallocator_d.cc @@ -244,7 +244,7 @@ void VCallocator_d::arbitrate_outvcs() int VCallocator_d::get_vnet(int invc) { - for(int i = 0; i < NUMBER_OF_VIRTUAL_NETWORKS; i++) + for(int i = 0; i < RubySystem::getNetwork()->getNumberOfVirtualNetworks(); i++) { if(invc >= (i*m_vc_per_vnet) && invc < ((i+1)*m_vc_per_vnet)) { diff --git a/src/mem/ruby/network/garnet-flexible-pipeline/GarnetNetwork.cc b/src/mem/ruby/network/garnet-flexible-pipeline/GarnetNetwork.cc index 2496cd30f..e56f5b5e8 100644 --- a/src/mem/ruby/network/garnet-flexible-pipeline/GarnetNetwork.cc +++ b/src/mem/ruby/network/garnet-flexible-pipeline/GarnetNetwork.cc @@ -44,26 +44,22 @@ #include "mem/ruby/network/garnet-flexible-pipeline/NetworkLink.hh" #include "mem/ruby/common/NetDest.hh" -// calls new to abstract away from the network -Network* Network::createNetwork(int nodes) +GarnetNetwork::GarnetNetwork(const string & name) + : Network(name) { - NetworkConfig::readNetConfig(); - // Instantiate a network depending on what kind of network is requested - if(NetworkConfig::isGarnetNetwork()) - { - if(NetworkConfig::isDetailNetwork()) - return new GarnetNetwork_d(nodes); - else - return new GarnetNetwork(nodes); - } - else - return new SimpleNetwork(nodes); } -GarnetNetwork::GarnetNetwork(int nodes) +void GarnetNetwork::init(const vector & argv) { - m_nodes = MachineType_base_number(MachineType_NUM); // Total nodes in network - m_virtual_networks = NUMBER_OF_VIRTUAL_NETWORKS; // Number of virtual networks = number of message classes in the coherence protocol +// printf("hello\n"); + Network::init(argv); +//added by SS +// assert (m_topology_ptr!=NULL); + + m_network_config_ptr = new NetworkConfig; + + m_network_config_ptr->init(argv); + m_ruby_start = 0; // Allocate to and from queues @@ -91,7 +87,8 @@ GarnetNetwork::GarnetNetwork(int nodes) } // Setup the network switches - m_topology_ptr = new Topology(this, m_nodes); + assert (m_topology_ptr!=NULL); + m_topology_ptr->makeTopology(); int number_of_routers = m_topology_ptr->numSwitches(); for (int i=0; i average_vc_load; - average_vc_load.setSize(m_virtual_networks*NetworkConfig::getVCsPerClass()); + average_vc_load.setSize(m_virtual_networks*m_network_config_ptr->getVCsPerClass()); - for(int i = 0; i < m_virtual_networks*NetworkConfig::getVCsPerClass(); i++) + for(int i = 0; i < m_virtual_networks*m_network_config_ptr->getVCsPerClass(); i++) { average_vc_load[i] = 0; } @@ -240,7 +238,7 @@ void GarnetNetwork::printStats(ostream& out) const Vector vc_load = m_link_ptr_vector[i]->getVcLoad(); for(int j = 0; j < vc_load.size(); j++) { - assert(vc_load.size() == NetworkConfig::getVCsPerClass()*m_virtual_networks); + assert(vc_load.size() == m_network_config_ptr->getVCsPerClass()*m_virtual_networks); average_vc_load[j] += vc_load[j]; } } @@ -248,7 +246,7 @@ void GarnetNetwork::printStats(ostream& out) const out << "Average Link Utilization :: " << average_link_utilization << " flits/cycle" <getVCsPerClass()*m_virtual_networks; i++) { average_vc_load[i] = (double(average_vc_load[i]) / (double(g_eventQueue_ptr->getTime()) - m_ruby_start)); out << "Average VC Load [" << i << "] = " << average_vc_load[i] << " flits/cycle" << endl; @@ -262,7 +260,7 @@ void GarnetNetwork::printConfig(ostream& out) const out << "Network Configuration" << endl; out << "---------------------" << endl; out << "network: GARNET_NETWORK" << endl; - out << "topology: " << g_NETWORK_TOPOLOGY << endl; + out << "topology: " << m_topology_ptr->getName() << endl; out << endl; for (int i = 0; i < m_virtual_networks; i++) @@ -295,10 +293,7 @@ void GarnetNetwork::printConfig(ostream& out) const { m_router_ptr_vector[i]->printConfig(out); } - if (g_PRINT_TOPOLOGY) - { - m_topology_ptr->printConfig(out); - } + m_topology_ptr->printConfig(out); } void GarnetNetwork::print(ostream& out) const diff --git a/src/mem/ruby/network/garnet-flexible-pipeline/GarnetNetwork.hh b/src/mem/ruby/network/garnet-flexible-pipeline/GarnetNetwork.hh index 27de3de07..194fef778 100644 --- a/src/mem/ruby/network/garnet-flexible-pipeline/GarnetNetwork.hh +++ b/src/mem/ruby/network/garnet-flexible-pipeline/GarnetNetwork.hh @@ -50,10 +50,15 @@ class NetworkLink; class GarnetNetwork : public Network{ public: - GarnetNetwork(int nodes); + GarnetNetwork(const string & name); ~GarnetNetwork(); + void init(const vector & argv); + + //added by SS + NetworkConfig* getNetworkConfig() { return m_network_config_ptr; } + // returns the queue requested for the given component MessageBuffer* getToNetQueue(NodeID id, bool ordered, int network_num); MessageBuffer* getFromNetQueue(NodeID id, bool ordered, int network_num); @@ -83,9 +88,10 @@ private: GarnetNetwork(const GarnetNetwork& obj); GarnetNetwork& operator=(const GarnetNetwork& obj); + /***********Data Members*************/ - int m_virtual_networks; - int m_nodes; +// int m_virtual_networks; +// int m_nodes; Vector m_in_use; Vector m_ordered; @@ -97,8 +103,10 @@ private: Vector m_link_ptr_vector; // All links in the network Vector m_ni_ptr_vector; // All NI's in Network - Topology* m_topology_ptr; +// Topology* m_topology_ptr; Time m_ruby_start; + + NetworkConfig* m_network_config_ptr; }; // Output operator declaration diff --git a/src/mem/ruby/network/garnet-flexible-pipeline/NetworkConfig.hh b/src/mem/ruby/network/garnet-flexible-pipeline/NetworkConfig.hh index 270fd6429..33af28a7e 100644 --- a/src/mem/ruby/network/garnet-flexible-pipeline/NetworkConfig.hh +++ b/src/mem/ruby/network/garnet-flexible-pipeline/NetworkConfig.hh @@ -43,14 +43,35 @@ #include "mem/ruby/config/RubyConfig.hh" class NetworkConfig { + private: + int m_flit_size; + int m_number_of_pipe_stages; + int m_vcs_per_class; + int m_buffer_size; + bool m_using_network_testing; public: - static bool isGarnetNetwork() {return g_GARNET_NETWORK; } - static bool isDetailNetwork() {return g_DETAIL_NETWORK; } - static int isNetworkTesting() {return g_NETWORK_TESTING; } - static int getFlitSize() {return g_FLIT_SIZE; } - static int getNumPipeStages() {return g_NUM_PIPE_STAGES; } - static int getVCsPerClass() {return g_VCS_PER_CLASS; } - static int getBufferSize() {return g_BUFFER_SIZE; } + NetworkConfig(){} + void init(const vector & argv) { + for (size_t i=0; igetTime()); - if(!NetworkConfig::isNetworkTesting()) // When we are doing network only testing, the messages do not have to be buffered into the message buffers + if(!m_net_ptr->getNetworkConfig()->isNetworkTesting()) // When we are doing network only testing, the messages do not have to be buffered into the message buffers { outNode_ptr[t_flit->get_vnet()]->enqueue(t_flit->get_msg_ptr(), 1); // enqueueing for protocol buffer. This is not required when doing network only testing } diff --git a/src/mem/ruby/network/garnet-flexible-pipeline/NetworkLink.cc b/src/mem/ruby/network/garnet-flexible-pipeline/NetworkLink.cc index 90177cbec..ddc92d44c 100644 --- a/src/mem/ruby/network/garnet-flexible-pipeline/NetworkLink.cc +++ b/src/mem/ruby/network/garnet-flexible-pipeline/NetworkLink.cc @@ -46,8 +46,8 @@ NetworkLink::NetworkLink(int id, int latency, GarnetNetwork *net_ptr) m_link_utilized = 0; m_net_ptr = net_ptr; m_latency = latency; - int num_net = NUMBER_OF_VIRTUAL_NETWORKS; - int num_vc = NetworkConfig::getVCsPerClass(); + int num_net = net_ptr->getNumberOfVirtualNetworks(); + int num_vc = m_net_ptr->getNetworkConfig()->getVCsPerClass(); m_vc_load.setSize(num_net*num_vc); for(int i = 0; i < num_net*num_vc; i++) diff --git a/src/mem/ruby/network/garnet-flexible-pipeline/Router.cc b/src/mem/ruby/network/garnet-flexible-pipeline/Router.cc index 1def6f9c3..ea32e938d 100644 --- a/src/mem/ruby/network/garnet-flexible-pipeline/Router.cc +++ b/src/mem/ruby/network/garnet-flexible-pipeline/Router.cc @@ -43,8 +43,8 @@ Router::Router(int id, GarnetNetwork *network_ptr) { m_id = id; m_net_ptr = network_ptr; - m_virtual_networks = NUMBER_OF_VIRTUAL_NETWORKS; - m_vc_per_vnet = NetworkConfig::getVCsPerClass(); + m_virtual_networks = m_net_ptr->getNumberOfVirtualNetworks(); + m_vc_per_vnet = m_net_ptr->getNetworkConfig()->getVCsPerClass(); m_round_robin_inport = 0; m_round_robin_start = 0; m_num_vcs = m_vc_per_vnet*m_virtual_networks; @@ -103,7 +103,7 @@ void Router::addOutPort(NetworkLink *out_link, const NetDest& routing_table_entr Vector intermediateQueues; for(int i = 0; i < m_num_vcs; i++) { - intermediateQueues.insertAtBottom(new flitBuffer(NetworkConfig::getBufferSize())); + intermediateQueues.insertAtBottom(new flitBuffer(m_net_ptr->getNetworkConfig()->getBufferSize())); } m_router_buffers.insertAtBottom(intermediateQueues); @@ -246,17 +246,17 @@ void Router::routeCompute(flit *m_flit, int inport) int outport = m_in_vc_state[inport][invc]->get_outport(); int outvc = m_in_vc_state[inport][invc]->get_outvc(); - assert(NetworkConfig::getNumPipeStages() >= 1); - m_flit->set_time(g_eventQueue_ptr->getTime() + (NetworkConfig::getNumPipeStages() - 1)); // Becasuse 1 cycle will be consumed in scheduling the output link + assert(m_net_ptr->getNetworkConfig()->getNumPipeStages() >= 1); + m_flit->set_time(g_eventQueue_ptr->getTime() + (m_net_ptr->getNetworkConfig()->getNumPipeStages() - 1)); // Becasuse 1 cycle will be consumed in scheduling the output link m_flit->set_vc(outvc); m_router_buffers[outport][outvc]->insert(m_flit); - if(NetworkConfig::getNumPipeStages() > 1) - g_eventQueue_ptr->scheduleEvent(this, NetworkConfig::getNumPipeStages() -1 ); + if(m_net_ptr->getNetworkConfig()->getNumPipeStages() > 1) + g_eventQueue_ptr->scheduleEvent(this, m_net_ptr->getNetworkConfig()->getNumPipeStages() -1 ); if((m_flit->get_type() == HEAD_) || (m_flit->get_type() == HEAD_TAIL_)) { NetDest destination = dynamic_cast(m_flit->get_msg_ptr().ref())->getInternalDestination(); - if(NetworkConfig::getNumPipeStages() > 1) + if(m_net_ptr->getNetworkConfig()->getNumPipeStages() > 1) { m_out_vc_state[outport][outvc]->setState(VC_AB_, g_eventQueue_ptr->getTime() + 1); m_out_link[outport]->request_vc_link(outvc, destination, g_eventQueue_ptr->getTime() + 1); diff --git a/src/mem/ruby/network/simple/CustomTopology.cc b/src/mem/ruby/network/simple/CustomTopology.cc new file mode 100644 index 000000000..829086f31 --- /dev/null +++ b/src/mem/ruby/network/simple/CustomTopology.cc @@ -0,0 +1,140 @@ + +#include "mem/ruby/network/simple/CustomTopology.hh" +#include "mem/protocol/MachineType.hh" + +static const int INFINITE_LATENCY = 10000; // Yes, this is a big hack +static const int DEFAULT_BW_MULTIPLIER = 1; // Just to be consistent with above :) + +// make a network as described by the networkFile +void CustomTopology::construct() +{ + + Vector< Vector < SwitchID > > nodePairs; // node pairs extracted from the file + Vector latencies; // link latencies for each link extracted + Vector bw_multis; // bw multipliers for each link extracted + Vector weights; // link weights used to enfore e-cube deadlock free routing + Vector< SwitchID > int_network_switches; // internal switches extracted from the file + Vector endpointConnectionExist; // used to ensure all endpoints are connected to the network + + endpointConnectionExist.setSize(m_nodes); + + // initialize endpoint check vector + for (int k = 0; k < endpointConnectionExist.size(); k++) { + endpointConnectionExist[k] = false; + } + + stringstream networkFile( m_connections ); + + string line = ""; + + while (!networkFile.eof()) { + + Vector < SwitchID > nodes; + nodes.setSize(2); + int latency = -1; // null latency + int weight = -1; // null weight + int bw_multiplier = DEFAULT_BW_MULTIPLIER; // default multiplier incase the network file doesn't define it + int i = 0; // node pair index + int varsFound = 0; // number of varsFound on the line + int internalNodes = 0; // used to determine if the link is between 2 internal nodes + std::getline(networkFile, line, '\n'); + string varStr = string_split(line, ' '); + + // parse the current line in the file + while (varStr != "") { + string label = string_split(varStr, ':'); + + // valid node labels + if (label == "ext_node" || label == "int_node") { + ASSERT(i < 2); // one link between 2 switches per line + varsFound++; + bool isNewIntSwitch = true; + if (label == "ext_node") { // input link to node + MachineType machine = string_to_MachineType(string_split(varStr, ':')); + string nodeStr = string_split(varStr, ':'); + nodes[i] = MachineType_base_number(machine) + + atoi(nodeStr.c_str()); + + // in nodes should be numbered 0 to m_nodes-1 + ASSERT(nodes[i] >= 0 && nodes[i] < m_nodes); + isNewIntSwitch = false; + endpointConnectionExist[nodes[i]] = true; + } + if (label == "int_node") { // interior node + nodes[i] = atoi((string_split(varStr, ':')).c_str())+m_nodes*2; + // in nodes should be numbered >= m_nodes*2 + ASSERT(nodes[i] >= m_nodes*2); + for (int k = 0; k < int_network_switches.size(); k++) { + if (int_network_switches[k] == nodes[i]) { + isNewIntSwitch = false; + } + } + if (isNewIntSwitch) { // if internal switch + m_number_of_switches++; + int_network_switches.insertAtBottom(nodes[i]); + } + internalNodes++; + } + i++; + } else if (label == "link_latency") { + latency = atoi((string_split(varStr, ':')).c_str()); + varsFound++; + } else if (label == "bw_multiplier") { // not necessary, defaults to DEFAULT_BW_MULTIPLIER + bw_multiplier = atoi((string_split(varStr, ':')).c_str()); + } else if (label == "link_weight") { // not necessary, defaults to link_latency + weight = atoi((string_split(varStr, ':')).c_str()); + } else { + cerr << "Error: Unexpected Identifier: " << label << endl; + exit(1); + } + varStr = string_split(line, ' '); + } + if (varsFound == 3) { // all three necessary link variables where found so add the link + nodePairs.insertAtBottom(nodes); + latencies.insertAtBottom(latency); + if (weight != -1) { + weights.insertAtBottom(weight); + } else { + weights.insertAtBottom(latency); + } + bw_multis.insertAtBottom(bw_multiplier); + Vector < SwitchID > otherDirectionNodes; + otherDirectionNodes.setSize(2); + otherDirectionNodes[0] = nodes[1]; + if (internalNodes == 2) { // this is an internal link + otherDirectionNodes[1] = nodes[0]; + } else { + otherDirectionNodes[1] = nodes[0]+m_nodes; + } + nodePairs.insertAtBottom(otherDirectionNodes); + latencies.insertAtBottom(latency); + if (weight != -1) { + weights.insertAtBottom(weight); + } else { + weights.insertAtBottom(latency); + } + bw_multis.insertAtBottom(bw_multiplier); + } else { + if (varsFound != 0) { // if this is not a valid link, then no vars should have been found + cerr << "Error in line: " << line << endl; + exit(1); + } + } + } // end of file + + // makes sure all enpoints are connected in the soon to be created network + for (int k = 0; k < endpointConnectionExist.size(); k++) { + if (endpointConnectionExist[k] == false) { + cerr << "Error: Unconnected Endpoint: " << k << endl; + exit(1); + } + } + + ASSERT(nodePairs.size() == latencies.size() && latencies.size() == bw_multis.size() && latencies.size() == weights.size()) + for (int k = 0; k < nodePairs.size(); k++) { + ASSERT(nodePairs[k].size() == 2); + addLink(nodePairs[k][0], nodePairs[k][1], latencies[k], bw_multis[k], weights[k]); + } + + // networkFile.close(); +} diff --git a/src/mem/ruby/network/simple/CustomTopology.hh b/src/mem/ruby/network/simple/CustomTopology.hh new file mode 100644 index 000000000..6c44eb049 --- /dev/null +++ b/src/mem/ruby/network/simple/CustomTopology.hh @@ -0,0 +1,17 @@ + +#ifndef CUSTOMTOPOLOGY_H +#define CUSTOMTOPOLOGY_H + +#include "mem/ruby/network/simple/Topology.hh" + +class CustomTopology : public Topology +{ +public: + CustomTopology(const string & name); + void init(const vector & argv); + +protected: + void construct(); +}; + +#endif diff --git a/src/mem/ruby/network/simple/HierarchicalSwitchTopology.cc b/src/mem/ruby/network/simple/HierarchicalSwitchTopology.cc new file mode 100644 index 000000000..c0190e789 --- /dev/null +++ b/src/mem/ruby/network/simple/HierarchicalSwitchTopology.cc @@ -0,0 +1,66 @@ + +#include "mem/ruby/network/simple/HierarchicalSwitchTopology.hh" + +// hierarchical switch topology +void Topology::construct(int fan_out_degree) +{ + // Make a row of switches with only one input. This extra row makes + // sure the links out of the nodes have latency and limited + // bandwidth. + + // number of inter-chip switches, i.e. the last row of switches + Vector last_level; + for (int i=0; igetLinkLatency()); + last_level.insertAtBottom(new_switch); + } + + // Create Hierarchical Switches + + // start from the bottom level and work up to root + Vector next_level; + while(last_level.size() > 1) { + for (int i=0; igetLinkLatency()); + } + + // Make the current level the last level to get ready for next + // iteration + last_level = next_level; + next_level.clear(); + } + + SwitchID root_switch = last_level[0]; + + Vector out_level; + for (int i=0; i fan_out_degree) { + next_level.insertAtBottom(newSwitchID()); + } else { + next_level.insertAtBottom(root_switch); + } + } + // Add this link to the last switch we created + addLink(next_level[next_level.size()-1], out_level[i], m_network_ptr->getLinkLatency()); + } + + // Make the current level the last level to get ready for next + // iteration + out_level = next_level; + next_level.clear(); + } +} diff --git a/src/mem/ruby/network/simple/HierarchicalSwitchTopology.hh b/src/mem/ruby/network/simple/HierarchicalSwitchTopology.hh new file mode 100644 index 000000000..0c2c84ef8 --- /dev/null +++ b/src/mem/ruby/network/simple/HierarchicalSwitchTopology.hh @@ -0,0 +1,17 @@ + +#ifndef HIERARCHICALSWITCHTOPOLOGY_H +#define HIERARCHICALSWITCHTOPOLOGY_H + +#include "mem/ruby/network/simple/Topology.hh" + +class HierarchicalSwitchTopology : public Topology +{ +public: + HierarchicalSwitchTopology(const string & name); + void init(const vector & argv); + +protected: + void construct(); +}; + +#endif diff --git a/src/mem/ruby/network/simple/PerfectSwitch.cc b/src/mem/ruby/network/simple/PerfectSwitch.cc index b561b69e2..4fd9af3eb 100644 --- a/src/mem/ruby/network/simple/PerfectSwitch.cc +++ b/src/mem/ruby/network/simple/PerfectSwitch.cc @@ -55,7 +55,7 @@ bool operator<(const LinkOrder& l1, const LinkOrder& l2) { PerfectSwitch::PerfectSwitch(SwitchID sid, SimpleNetwork* network_ptr) { - m_virtual_networks = NUMBER_OF_VIRTUAL_NETWORKS; // FIXME - pass me as a parameter? + m_virtual_networks = network_ptr->getNumberOfVirtualNetworks(); m_switch_id = sid; m_round_robin_start = 0; m_network_ptr = network_ptr; @@ -88,9 +88,9 @@ void PerfectSwitch::addOutPort(const Vector& out, const NetDest& m_out.insertAtBottom(out); m_routing_table.insertAtBottom(routing_table_entry); - if (g_PRINT_TOPOLOGY) { + // if (RubyConfig::getPrintTopology()) { m_out_link_vec.insertAtBottom(out); - } + // } } void PerfectSwitch::clearRoutingTables() @@ -134,6 +134,7 @@ void PerfectSwitch::wakeup() int highest_prio_vnet = m_virtual_networks-1; int lowest_prio_vnet = 0; int decrementer = 1; + bool schedule_wakeup = false; NetworkMessage* net_msg_ptr = NULL; // invert priorities to avoid starvation seen in the component network @@ -186,8 +187,9 @@ void PerfectSwitch::wakeup() assert(m_link_order.size() == m_routing_table.size()); assert(m_link_order.size() == m_out.size()); - - if (g_adaptive_routing) { +//changed by SS +// if (RubyConfig::getAdaptiveRouting()) { + if (m_network_ptr->getAdaptiveRouting()) { if (m_network_ptr->isVNetOrdered(vnet)) { // Don't adaptively route for (int outlink=0; outlink > nodePairs; // node pairs extracted from the file + Vector latencies; // link latencies for each link extracted + Vector bw_multis; // bw multipliers for each link extracted + + Vector < SwitchID > nodes; + nodes.setSize(2); + + // number of inter-chip switches + int numberOfChipSwitches = m_nodes/MachineType_base_level(MachineType_NUM); + // two switches per machine node grouping + // one intra-chip switch and one inter-chip switch per chip + for(int i=0; igetOnChipLinkLatency(); // internal link latency + int bw_multiplier = 10; // external link bw multiplier of the global bandwidth + + nodes[0] = chip+m_nodes*2; + nodes[1] = chip+m_nodes*2+RubyConfig::getNumberOfChips(); + + // insert link + nodePairs.insertAtBottom(nodes); + latencies.insertAtBottom(latency); + bw_multis.insertAtBottom(bw_multiplier); + + // opposite direction link + Vector < SwitchID > otherDirectionNodes; + otherDirectionNodes.setSize(2); + otherDirectionNodes[0] = nodes[1]; + otherDirectionNodes[1] = nodes[0]; + nodePairs.insertAtBottom(otherDirectionNodes); + latencies.insertAtBottom(latency); + bw_multis.insertAtBottom(bw_multiplier); + } + + // point-to-point network between chips + for (int chip = 0; chip < RubyConfig::getNumberOfChips(); chip++) { + for (int other_chip = chip+1; other_chip < RubyConfig::getNumberOfChips(); other_chip++) { + + int latency = m_network_ptr->getOffChipLinkLatency(); // external link latency + int bw_multiplier = 1; // external link bw multiplier of the global bandwidth + + nodes[0] = chip+m_nodes*2+RubyConfig::getNumberOfChips(); + nodes[1] = other_chip+m_nodes*2+RubyConfig::getNumberOfChips(); + + // insert link + nodePairs.insertAtBottom(nodes); + latencies.insertAtBottom(latency); + bw_multis.insertAtBottom(bw_multiplier); + + // opposite direction link + Vector < SwitchID > otherDirectionNodes; + otherDirectionNodes.setSize(2); + otherDirectionNodes[0] = nodes[1]; + otherDirectionNodes[1] = nodes[0]; + nodePairs.insertAtBottom(otherDirectionNodes); + latencies.insertAtBottom(latency); + bw_multis.insertAtBottom(bw_multiplier); + } + } + + // add links + ASSERT(nodePairs.size() == latencies.size() && latencies.size() == bw_multis.size()) + for (int k = 0; k < nodePairs.size(); k++) { + ASSERT(nodePairs[k].size() == 2); + addLink(nodePairs[k][0], nodePairs[k][1], latencies[k], bw_multis[k]); + } +} diff --git a/src/mem/ruby/network/simple/PtToPtTopology.hh b/src/mem/ruby/network/simple/PtToPtTopology.hh new file mode 100644 index 000000000..f15fa5956 --- /dev/null +++ b/src/mem/ruby/network/simple/PtToPtTopology.hh @@ -0,0 +1,17 @@ + +#ifndef PTTOPTTOPOLOGY_H +#define PTTOPTTOPOLOGY_H + +#include "mem/ruby/network/simple/Topology.hh" + +class PtToPtTopology : public Topology +{ +public: + PtToPtTopology(const string & name); + void init(const vector & argv); + +protected: + void construct(); +}; + +#endif diff --git a/src/mem/ruby/network/simple/SimpleNetwork.cc b/src/mem/ruby/network/simple/SimpleNetwork.cc index 1d0567b6e..1a3b876bf 100644 --- a/src/mem/ruby/network/simple/SimpleNetwork.cc +++ b/src/mem/ruby/network/simple/SimpleNetwork.cc @@ -59,11 +59,55 @@ Network* Network::createNetwork(int nodes) } */ +SimpleNetwork::SimpleNetwork(const string & name) + : Network(name) +{ + m_virtual_networks = 0; + m_topology_ptr = NULL; +} + +void SimpleNetwork::init(const vector & argv) +{ + + Network::init(argv); + + m_endpoint_switches.setSize(m_nodes); + + m_in_use.setSize(m_virtual_networks); + m_ordered.setSize(m_virtual_networks); + for (int i = 0; i < m_virtual_networks; i++) { + m_in_use[i] = false; + m_ordered[i] = false; + } + + // Allocate to and from queues + m_toNetQueues.setSize(m_nodes); + m_fromNetQueues.setSize(m_nodes); + for (int node = 0; node < m_nodes; node++) { + m_toNetQueues[node].setSize(m_virtual_networks); + m_fromNetQueues[node].setSize(m_virtual_networks); + for (int j = 0; j < m_virtual_networks; j++) { + cerr << "Creating new MessageBuffer for " << node << " " << j << endl; + m_toNetQueues[node][j] = new MessageBuffer; + m_fromNetQueues[node][j] = new MessageBuffer; + } + } + + // Setup the network switches + // m_topology_ptr = new Topology(this, m_nodes); + m_topology_ptr->makeTopology(); + int number_of_switches = m_topology_ptr->numSwitches(); + for (int i=0; icreateLinks(false); // false because this isn't a reconfiguration +} +/* SimpleNetwork::SimpleNetwork(int nodes) { m_nodes = MachineType_base_number(MachineType_NUM); - m_virtual_networks = NUMBER_OF_VIRTUAL_NETWORKS; + m_virtual_networks = RubyConfig::getNumberOfVirtualNetworks(); m_endpoint_switches.setSize(m_nodes); m_in_use.setSize(m_virtual_networks); @@ -93,7 +137,7 @@ SimpleNetwork::SimpleNetwork(int nodes) } m_topology_ptr->createLinks(false); // false because this isn't a reconfiguration } - +*/ void SimpleNetwork::reset() { for (int node = 0; node < m_nodes; node++) { @@ -154,8 +198,8 @@ void SimpleNetwork::makeInternalLink(SwitchID src, SwitchID dest, const NetDest& // allocate a buffer MessageBuffer* buffer_ptr = new MessageBuffer; buffer_ptr->setOrdering(true); - if(FINITE_BUFFERING) { - buffer_ptr->setSize(FINITE_BUFFER_SIZE); + if (m_buffer_size > 0) { + buffer_ptr->setSize(m_buffer_size); } queues.insertAtBottom(buffer_ptr); // remember to deallocate it @@ -225,7 +269,7 @@ void SimpleNetwork::printConfig(ostream& out) const out << "Network Configuration" << endl; out << "---------------------" << endl; out << "network: SIMPLE_NETWORK" << endl; - out << "topology: " << g_NETWORK_TOPOLOGY << endl; + out << "topology: " << m_topology_ptr->getName() << endl; out << endl; for (int i = 0; i < m_virtual_networks; i++) { @@ -246,9 +290,7 @@ void SimpleNetwork::printConfig(ostream& out) const m_switch_ptr_vector[i]->printConfig(out); } - if (g_PRINT_TOPOLOGY) { - m_topology_ptr->printConfig(out); - } + m_topology_ptr->printConfig(out); } void SimpleNetwork::print(ostream& out) const diff --git a/src/mem/ruby/network/simple/SimpleNetwork.hh b/src/mem/ruby/network/simple/SimpleNetwork.hh index 39ee2c095..9ffd862d3 100644 --- a/src/mem/ruby/network/simple/SimpleNetwork.hh +++ b/src/mem/ruby/network/simple/SimpleNetwork.hh @@ -83,11 +83,14 @@ class Topology; class SimpleNetwork : public Network { public: // Constructors - SimpleNetwork(int nodes); + // SimpleNetwork(int nodes); + SimpleNetwork(const string & name); // Destructor ~SimpleNetwork(); + void init(const vector & argv); + // Public Methods void printStats(ostream& out) const; void clearStats(); @@ -130,14 +133,11 @@ private: Vector > m_toNetQueues; Vector > m_fromNetQueues; - int m_nodes; - int m_virtual_networks; Vector m_in_use; Vector m_ordered; Vector m_switch_ptr_vector; Vector m_buffers_to_free; Vector m_endpoint_switches; - Topology* m_topology_ptr; }; // Output operator declaration diff --git a/src/mem/ruby/network/simple/Switch.cc b/src/mem/ruby/network/simple/Switch.cc index 192520e85..e3420ddae 100644 --- a/src/mem/ruby/network/simple/Switch.cc +++ b/src/mem/ruby/network/simple/Switch.cc @@ -82,8 +82,9 @@ void Switch::addOutPort(const Vector& out, const NetDest& routin MessageBuffer* buffer_ptr = new MessageBuffer; // Make these queues ordered buffer_ptr->setOrdering(true); - if(FINITE_BUFFERING) { - buffer_ptr->setSize(FINITE_BUFFER_SIZE); + Network* net_ptr = RubySystem::getNetwork(); + if(net_ptr->getBufferSize() > 0) { + buffer_ptr->setSize(net_ptr->getBufferSize()); } intermediateBuffers.insertAtBottom(buffer_ptr); m_buffers_to_free.insertAtBottom(buffer_ptr); diff --git a/src/mem/ruby/network/simple/Switch.hh b/src/mem/ruby/network/simple/Switch.hh index 58bde05ea..193898928 100644 --- a/src/mem/ruby/network/simple/Switch.hh +++ b/src/mem/ruby/network/simple/Switch.hh @@ -52,6 +52,7 @@ class PerfectSwitch; class NetDest; class SimpleNetwork; class Throttle; +class Network; class Switch { public: @@ -83,6 +84,7 @@ private: // Data Members (m_ prefix) PerfectSwitch* m_perfect_switch_ptr; + Network* m_network_ptr; Vector m_throttles; Vector m_buffers_to_free; SwitchID m_switch_id; diff --git a/src/mem/ruby/network/simple/Throttle.cc b/src/mem/ruby/network/simple/Throttle.cc index f91bbdb30..1cfe88987 100644 --- a/src/mem/ruby/network/simple/Throttle.cc +++ b/src/mem/ruby/network/simple/Throttle.cc @@ -103,9 +103,9 @@ void Throttle::addLinks(const Vector& in_vec, const Vector ADJUST_INTERVAL) { double utilization = m_bandwidth_since_sample/double(ADJUST_INTERVAL * getLinkBandwidth()); - if (utilization > g_bash_bandwidth_adaptive_threshold) { - // Used more bandwidth - m_bash_counter++; - } else { - // Used less bandwidth - m_bash_counter--; - } + // Used less bandwidth + m_bash_counter--; // Make sure we don't overflow m_bash_counter = min(HIGH_RANGE, m_bash_counter); diff --git a/src/mem/ruby/network/simple/Throttle.hh b/src/mem/ruby/network/simple/Throttle.hh index 067c7af5f..7b6d04353 100644 --- a/src/mem/ruby/network/simple/Throttle.hh +++ b/src/mem/ruby/network/simple/Throttle.hh @@ -46,7 +46,8 @@ #include "mem/gems_common/Vector.hh" #include "mem/ruby/common/Consumer.hh" #include "mem/ruby/system/NodeID.hh" -#include "mem/ruby/config/RubyConfig.hh" +#include "mem/ruby/system/System.hh" +#include "mem/ruby/network/Network.hh" class MessageBuffer; @@ -68,7 +69,7 @@ public: void clearStats(); void printConfig(ostream& out) const; double getUtilization() const; // The average utilization (a percent) since last clearStats() - int getLinkBandwidth() const { return g_endpoint_bandwidth * m_link_bandwidth_multiplier; } + int getLinkBandwidth() const { return RubySystem::getNetwork()->getEndpointBandwidth() * m_link_bandwidth_multiplier; } int getLatency() const { return m_link_latency; } const Vector >& getCounters() const { return m_message_counters; } diff --git a/src/mem/ruby/network/simple/Topology.cc b/src/mem/ruby/network/simple/Topology.cc index f887f2a04..742bfe3cd 100644 --- a/src/mem/ruby/network/simple/Topology.cc +++ b/src/mem/ruby/network/simple/Topology.cc @@ -40,10 +40,11 @@ #include "mem/ruby/common/NetDest.hh" #include "mem/ruby/network/Network.hh" #include "mem/protocol/TopologyType.hh" -#include "mem/ruby/config/RubyConfig.hh" +//#include "mem/ruby/config/RubyConfig.hh" #include "mem/gems_common/util.hh" #include "mem/protocol/MachineType.hh" #include "mem/protocol/Protocol.hh" +#include "mem/ruby/system/System.hh" #include static const int INFINITE_LATENCY = 10000; // Yes, this is a big hack @@ -57,359 +58,45 @@ static const int DEFAULT_BW_MULTIPLIER = 1; // Just to be consistent with above // of the network. // Helper functions based on chapter 29 of Cormen et al. -static void extend_shortest_path(Matrix& current_dist, Matrix& latencies, Matrix& inter_switches); +static Matrix extend_shortest_path(const Matrix& current_dist, Matrix& latencies, Matrix& inter_switches); static Matrix shortest_path(const Matrix& weights, Matrix& latencies, Matrix& inter_switches); static bool link_is_shortest_path_to_node(SwitchID src, SwitchID next, SwitchID final, const Matrix& weights, const Matrix& dist); static NetDest shortest_path_to_node(SwitchID src, SwitchID next, const Matrix& weights, const Matrix& dist); - -Topology::Topology(Network* network_ptr, int number_of_nodes) +Topology::Topology(const string & name) + : m_name(name) { - m_network_ptr = network_ptr; - m_nodes = number_of_nodes; + m_network_ptr = NULL; + m_nodes = MachineType_base_number(MachineType_NUM); m_number_of_switches = 0; - init(); -} - -void Topology::init() -{ - if (m_nodes == 1) { - SwitchID id = newSwitchID(); - addLink(0, id, NETWORK_LINK_LATENCY); - addLink(id, 1, NETWORK_LINK_LATENCY); - return; - } - - // topology-specific set-up - TopologyType topology = string_to_TopologyType(g_NETWORK_TOPOLOGY); - switch (topology) { - case TopologyType_TORUS_2D: - make2DTorus(); - break; - case TopologyType_HIERARCHICAL_SWITCH: - makeHierarchicalSwitch(FAN_OUT_DEGREE); - break; - case TopologyType_CROSSBAR: - makeHierarchicalSwitch(1024); - break; - case TopologyType_PT_TO_PT: - makePtToPt(); - break; - case TopologyType_FILE_SPECIFIED: - makeFileSpecified(); - break; - default: - ERROR_MSG("Unexpected typology type") - } - - // initialize component latencies record - m_component_latencies.setSize(0); - m_component_inter_switches.setSize(0); -} - -void Topology::makeSwitchesPerChip(Vector< Vector < SwitchID > > &nodePairs, Vector &latencies, Vector &bw_multis, int numberOfChipSwitches) -{ - - Vector < SwitchID > nodes; // temporary buffer - nodes.setSize(2); - - Vector endpointConnectionExist; // used to ensure all endpoints are connected to the network - endpointConnectionExist.setSize(m_nodes); - // initialize endpoint check vector - for (int k = 0; k < endpointConnectionExist.size(); k++) { - endpointConnectionExist[k] = false; - } - - Vector componentCount; - componentCount.setSize(MachineType_NUM); - for (MachineType mType = MachineType_FIRST; mType < MachineType_NUM; ++mType) { - componentCount[mType] = 0; - } - - // components to/from network links - for (int chip = 0; chip < RubyConfig::numberOfChips(); chip++) { - for (MachineType mType = MachineType_FIRST; mType < MachineType_NUM; ++mType) { - for (int component = 0; component < MachineType_chip_count(mType, chip); component++) { - - int latency = -1; - int bw_multiplier = -1; // internal link bw multiplier of the global bandwidth - if (mType != MachineType_Directory) { - latency = ON_CHIP_LINK_LATENCY; // internal link latency - bw_multiplier = 10; // internal link bw multiplier of the global bandwidth - } else { - latency = NETWORK_LINK_LATENCY; // local memory latency - bw_multiplier = 1; // local memory link bw multiplier of the global bandwidth - } - nodes[0] = MachineType_base_number(mType)+componentCount[mType]; - nodes[1] = chip+m_nodes*2; // this is the chip's internal switch id # - - // insert link - nodePairs.insertAtBottom(nodes); - latencies.insertAtBottom(latency); - //bw_multis.insertAtBottom(bw_multiplier); - bw_multis.insertAtBottom(componentCount[mType]+MachineType_base_number((MachineType)mType)); - - // opposite direction link - Vector < SwitchID > otherDirectionNodes; - otherDirectionNodes.setSize(2); - otherDirectionNodes[0] = nodes[1]; - otherDirectionNodes[1] = nodes[0]+m_nodes; - nodePairs.insertAtBottom(otherDirectionNodes); - latencies.insertAtBottom(latency); - bw_multis.insertAtBottom(bw_multiplier); - - assert(!endpointConnectionExist[nodes[0]]); - endpointConnectionExist[nodes[0]] = true; - componentCount[mType]++; - } - } - } - - // make sure all enpoints are connected in the soon to be created network - for (int k = 0; k < endpointConnectionExist.size(); k++) { - if (endpointConnectionExist[k] == false) { - cerr << "Error: Unconnected Endpoint: " << k << endl; - exit(1); - } - } - - // secondary check to ensure we saw the correct machine counts - for (MachineType mType = MachineType_FIRST; mType < MachineType_NUM; ++mType) { - assert(componentCount[mType] == MachineType_base_count((MachineType)mType)); - } - -} - -// 2D torus topology - -void Topology::make2DTorus() -{ - Vector< Vector < SwitchID > > nodePairs; // node pairs extracted from the file - Vector latencies; // link latencies for each link extracted - Vector bw_multis; // bw multipliers for each link extracted - - Vector < SwitchID > nodes; // temporary buffer - nodes.setSize(2); - - // number of inter-chip switches - int numberOfTorusSwitches = m_nodes/MachineType_base_level(MachineType_NUM); - // one switch per machine node grouping - Vector torusSwitches; - for(int i=0; i= 2*m_nodes+numberOfTorusSwitches){ // determine if node is on the bottom - // sorin: bad bug if this is a > instead of a >= - nodes[1] = nodes[0] + lengthOfSide - (lengthOfSide*lengthOfSide); - } else { - nodes[1] = nodes[0] + lengthOfSide; - } - nodePairs.insertAtBottom(nodes); - latencies.insertAtBottom(latency); - bw_multis.insertAtBottom(bw_multiplier); - - } - - // add links - ASSERT(nodePairs.size() == latencies.size() && latencies.size() == bw_multis.size()) - for (int k = 0; k < nodePairs.size(); k++) { - ASSERT(nodePairs[k].size() == 2); - addLink(nodePairs[k][0], nodePairs[k][1], latencies[k], bw_multis[k]); - } - } -// hierarchical switch topology -void Topology::makeHierarchicalSwitch(int fan_out_degree) +void Topology::init(const vector & argv) { - // Make a row of switches with only one input. This extra row makes - // sure the links out of the nodes have latency and limited - // bandwidth. - - // number of inter-chip switches, i.e. the last row of switches - Vector last_level; - for (int i=0; i next_level; - while(last_level.size() > 1) { - for (int i=0; i out_level; - for (int i=0; i fan_out_degree) { - next_level.insertAtBottom(newSwitchID()); - } else { - next_level.insertAtBottom(root_switch); - } - } - // Add this link to the last switch we created - addLink(next_level[next_level.size()-1], out_level[i], NETWORK_LINK_LATENCY); + for (size_t i=0; i > nodePairs; // node pairs extracted from the file - Vector latencies; // link latencies for each link extracted - Vector bw_multis; // bw multipliers for each link extracted - - Vector < SwitchID > nodes; - nodes.setSize(2); - - // number of inter-chip switches - int numberOfChipSwitches = m_nodes/MachineType_base_level(MachineType_NUM); - // two switches per machine node grouping - // one intra-chip switch and one inter-chip switch per chip - for(int i=0; i otherDirectionNodes; - otherDirectionNodes.setSize(2); - otherDirectionNodes[0] = nodes[1]; - otherDirectionNodes[1] = nodes[0]; - nodePairs.insertAtBottom(otherDirectionNodes); - latencies.insertAtBottom(latency); - bw_multis.insertAtBottom(bw_multiplier); - } - - // point-to-point network between chips - for (int chip = 0; chip < RubyConfig::numberOfChips(); chip++) { - for (int other_chip = chip+1; other_chip < RubyConfig::numberOfChips(); other_chip++) { - - int latency = NETWORK_LINK_LATENCY; // external link latency - int bw_multiplier = 1; // external link bw multiplier of the global bandwidth - - nodes[0] = chip+m_nodes*2+RubyConfig::numberOfChips(); - nodes[1] = other_chip+m_nodes*2+RubyConfig::numberOfChips(); - - // insert link - nodePairs.insertAtBottom(nodes); - latencies.insertAtBottom(latency); - bw_multis.insertAtBottom(bw_multiplier); - - // opposite direction link - Vector < SwitchID > otherDirectionNodes; - otherDirectionNodes.setSize(2); - otherDirectionNodes[0] = nodes[1]; - otherDirectionNodes[1] = nodes[0]; - nodePairs.insertAtBottom(otherDirectionNodes); - latencies.insertAtBottom(latency); - bw_multis.insertAtBottom(bw_multiplier); - } - } - - // add links - ASSERT(nodePairs.size() == latencies.size() && latencies.size() == bw_multis.size()) - for (int k = 0; k < nodePairs.size(); k++) { - ASSERT(nodePairs[k].size() == 2); - addLink(nodePairs[k][0], nodePairs[k][1], latencies[k], bw_multis[k]); + /* + if (m_nodes == 1) { + SwitchID id = newSwitchID(); + addLink(0, id, m_network_ptr->getOffChipLinkLatency()); + addLink(id, 1, m_network_ptr->getOffChipLinkLatency()); + return; } -} - -// make a network as described by the networkFile -void Topology::makeFileSpecified() -{ + */ + assert(m_nodes > 1); Vector< Vector < SwitchID > > nodePairs; // node pairs extracted from the file Vector latencies; // link latencies for each link extracted @@ -425,21 +112,7 @@ void Topology::makeFileSpecified() endpointConnectionExist[k] = false; } - string filename = "network/simple/Network_Files/"; - filename = filename+g_CACHE_DESIGN - +"_Procs-"+int_to_string(RubyConfig::numberOfProcessors()) - +"_ProcsPerChip-"+int_to_string(RubyConfig::numberOfProcsPerChip()) - +"_L2Banks-"+int_to_string(RubyConfig::numberOfL2Cache()) - +"_Memories-"+int_to_string(RubyConfig::numberOfMemories()) - +".txt"; - - ifstream networkFile( filename.c_str() , ios::in); - if (!networkFile.is_open()) { - cerr << "Error: Could not open network file: " << filename << endl; - cerr << "Probably no network file exists for " << RubyConfig::numberOfProcessors() - << " processors and " << RubyConfig::numberOfProcsPerChip() << " procs per chip " << endl; - exit(1); - } + stringstream networkFile( m_connections ); string line = ""; @@ -468,14 +141,9 @@ void Topology::makeFileSpecified() if (label == "ext_node") { // input link to node MachineType machine = string_to_MachineType(string_split(varStr, ':')); string nodeStr = string_split(varStr, ':'); - if (string_split(varStr, ':') == "bank") { - nodes[i] = MachineType_base_number(machine) - + atoi(nodeStr.c_str()) - + atoi((string_split(varStr, ':')).c_str())*RubyConfig::numberOfChips(); - } else { - nodes[i] = MachineType_base_number(machine) - + atoi(nodeStr.c_str()); - } + nodes[i] = MachineType_base_number(machine) + + atoi(nodeStr.c_str()); + // in nodes should be numbered 0 to m_nodes-1 ASSERT(nodes[i] >= 0 && nodes[i] < m_nodes); isNewIntSwitch = false; @@ -504,16 +172,6 @@ void Topology::makeFileSpecified() bw_multiplier = atoi((string_split(varStr, ':')).c_str()); } else if (label == "link_weight") { // not necessary, defaults to link_latency weight = atoi((string_split(varStr, ':')).c_str()); - } else if (label == "processors") { - ASSERT(atoi((string_split(varStr, ':')).c_str()) == RubyConfig::numberOfProcessors()); - } else if (label == "bw_unit") { - ASSERT(atoi((string_split(varStr, ':')).c_str()) == g_endpoint_bandwidth); - } else if (label == "procs_per_chip") { - ASSERT(atoi((string_split(varStr, ':')).c_str()) == RubyConfig::numberOfProcsPerChip()); - } else if (label == "L2banks") { - ASSERT(atoi((string_split(varStr, ':')).c_str()) == RubyConfig::numberOfL2Cache()); - } else if (label == "memories") { - ASSERT(atoi((string_split(varStr, ':')).c_str()) == RubyConfig::numberOfMemories()); } else { cerr << "Error: Unexpected Identifier: " << label << endl; exit(1); @@ -567,9 +225,12 @@ void Topology::makeFileSpecified() addLink(nodePairs[k][0], nodePairs[k][1], latencies[k], bw_multis[k], weights[k]); } - networkFile.close(); + // initialize component latencies record + m_component_latencies.setSize(0); + m_component_inter_switches.setSize(0); } + void Topology::createLinks(bool isReconfiguration) { // Find maximum switchID @@ -633,6 +294,82 @@ void Topology::createLinks(bool isReconfiguration) } } } +/* +void Topology::makeSwitchesPerChip(Vector< Vector < SwitchID > > &nodePairs, Vector &latencies, Vector &bw_multis, int numberOfChipSwitches) +{ + + Vector < SwitchID > nodes; // temporary buffer + nodes.setSize(2); + + Vector endpointConnectionExist; // used to ensure all endpoints are connected to the network + endpointConnectionExist.setSize(m_nodes); + // initialize endpoint check vector + for (int k = 0; k < endpointConnectionExist.size(); k++) { + endpointConnectionExist[k] = false; + } + + Vector componentCount; + componentCount.setSize(MachineType_NUM); + for (MachineType mType = MachineType_FIRST; mType < MachineType_NUM; ++mType) { + componentCount[mType] = 0; + } + + // components to/from network links + // TODO: drh5: bring back chips!!! + for (int chip = 0; chip < RubyConfig::getNumberOfChips(); chip++) { + for (MachineType mType = MachineType_FIRST; mType < MachineType_NUM; ++mType) { + for (int component = 0; component < MachineType_base_count(mType); component++) { + + int latency = -1; + int bw_multiplier = -1; // internal link bw multiplier of the global bandwidth + if (mType != MachineType_Directory) { + latency = RubyConfig::getOnChipLinkLatency(); // internal link latency + bw_multiplier = 10; // internal link bw multiplier of the global bandwidth + } else { + latency = RubyConfig::getNetworkLinkLatency(); // local memory latency + bw_multiplier = 1; // local memory link bw multiplier of the global bandwidth + } + nodes[0] = MachineType_base_number(mType)+componentCount[mType]; + nodes[1] = chip+m_nodes*2; // this is the chip's internal switch id # + + // insert link + nodePairs.insertAtBottom(nodes); + latencies.insertAtBottom(latency); + bw_multis.insertAtBottom(bw_multiplier); + //bw_multis.insertAtBottom(componentCount[mType]+MachineType_base_number((MachineType)mType)); + + // opposite direction link + Vector < SwitchID > otherDirectionNodes; + otherDirectionNodes.setSize(2); + otherDirectionNodes[0] = nodes[1]; + otherDirectionNodes[1] = nodes[0]+m_nodes; + nodePairs.insertAtBottom(otherDirectionNodes); + latencies.insertAtBottom(latency); + bw_multis.insertAtBottom(bw_multiplier); + + assert(!endpointConnectionExist[nodes[0]]); + endpointConnectionExist[nodes[0]] = true; + componentCount[mType]++; + } + } + } + + // make sure all enpoints are connected in the soon to be created network + for (int k = 0; k < endpointConnectionExist.size(); k++) { + if (endpointConnectionExist[k] == false) { + cerr << "Error: Unconnected Endpoint: " << k << endl; + exit(1); + } + } + + // secondary check to ensure we saw the correct machine counts + for (MachineType mType = MachineType_FIRST; mType < MachineType_NUM; ++mType) { + assert(componentCount[mType] == MachineType_base_count((MachineType)mType)); + } + +} +*/ + SwitchID Topology::newSwitchID() { @@ -680,6 +417,8 @@ void Topology::makeLink(SwitchID src, SwitchID dest, const NetDest& routing_tabl void Topology::printConfig(ostream& out) const { + if (m_print_config == false) return; + assert(m_component_latencies.size() > 0); out << "--- Begin Topology Print ---" << endl; diff --git a/src/mem/ruby/network/simple/Topology.hh b/src/mem/ruby/network/simple/Topology.hh index cb6c36f17..0f8cdff3b 100644 --- a/src/mem/ruby/network/simple/Topology.hh +++ b/src/mem/ruby/network/simple/Topology.hh @@ -59,21 +59,26 @@ typedef Vector < Vector > Matrix; class Topology { public: // Constructors - Topology(Network* network_ptr, int number_of_nodes); + // Topology(Network* network_ptr, int number_of_nodes); + Topology(const string & name); // Destructor - ~Topology() {} + virtual ~Topology() {} + + virtual void init(const vector & argv); // Public Methods + void makeTopology(); int numSwitches() const { return m_number_of_switches; } void createLinks(bool isReconfiguration); + const string getName() { return m_name; } void printStats(ostream& out) const {} void clearStats() {} void printConfig(ostream& out) const; void print(ostream& out) const { out << "[Topology]"; } -private: +protected: // Private Methods void init(); SwitchID newSwitchID(); @@ -82,12 +87,7 @@ private: void addLink(SwitchID src, SwitchID dest, int link_latency, int bw_multiplier, int link_weight); void makeLink(SwitchID src, SwitchID dest, const NetDest& routing_table_entry, int link_latency, int weight, int bw_multiplier, bool isReconfiguration); - void makeHierarchicalSwitch(int fan_out_degree); - void make2DTorus(); - void makePtToPt(); - void makeFileSpecified(); - - void makeSwitchesPerChip(Vector< Vector < SwitchID > > &nodePairs, Vector &latencies, Vector &bw_multis, int numberOfChips); + // void makeSwitchesPerChip(Vector< Vector < SwitchID > > &nodePairs, Vector &latencies, Vector &bw_multis, int numberOfChips); string getDesignStr(); // Private copy constructor and assignment operator @@ -95,7 +95,10 @@ private: Topology& operator=(const Topology& obj); // Data Members (m_ prefix) + string m_name; + bool m_print_config; Network* m_network_ptr; + string m_connections; NodeID m_nodes; int m_number_of_switches; diff --git a/src/mem/ruby/network/simple/Torus2DTopology.cc b/src/mem/ruby/network/simple/Torus2DTopology.cc new file mode 100644 index 000000000..e66c6dc0b --- /dev/null +++ b/src/mem/ruby/network/simple/Torus2DTopology.cc @@ -0,0 +1,84 @@ + +// 2D torus topology + +void Torus2DTopology::construct() +{ + Vector< Vector < SwitchID > > nodePairs; // node pairs extracted from the file + Vector latencies; // link latencies for each link extracted + Vector bw_multis; // bw multipliers for each link extracted + + Vector < SwitchID > nodes; // temporary buffer + nodes.setSize(2); + + // number of inter-chip switches + int numberOfTorusSwitches = m_nodes/MachineType_base_level(MachineType_NUM); + // one switch per machine node grouping + Vector torusSwitches; + for(int i=0; igetLinkLatency(); // external link latency + int bw_multiplier = 1; // external link bw multiplier of the global bandwidth + + for(int i=0; i= 2*m_nodes+numberOfTorusSwitches){ // determine if node is on the bottom + // sorin: bad bug if this is a > instead of a >= + nodes[1] = nodes[0] + lengthOfSide - (lengthOfSide*lengthOfSide); + } else { + nodes[1] = nodes[0] + lengthOfSide; + } + nodePairs.insertAtBottom(nodes); + latencies.insertAtBottom(latency); + bw_multis.insertAtBottom(bw_multiplier); + + } + + // add links + ASSERT(nodePairs.size() == latencies.size() && latencies.size() == bw_multis.size()) + for (int k = 0; k < nodePairs.size(); k++) { + ASSERT(nodePairs[k].size() == 2); + addLink(nodePairs[k][0], nodePairs[k][1], latencies[k], bw_multis[k]); + } + +} diff --git a/src/mem/ruby/network/simple/Torus2DTopology.hh b/src/mem/ruby/network/simple/Torus2DTopology.hh new file mode 100644 index 000000000..83a314e94 --- /dev/null +++ b/src/mem/ruby/network/simple/Torus2DTopology.hh @@ -0,0 +1,17 @@ + +#ifndef TORUS2DTOPOLOGY_H +#define TORUS2DTOPOLOGY_H + +#include "mem/ruby/network/simple/Topology.hh" + +class Torus2DTopology : public Topology +{ +public: + Torus2DTopology(const string & name); + void init(const vector & argv); + +protected: + void construct(); +}; + +#endif diff --git a/src/mem/ruby/profiler/AddressProfiler.cc b/src/mem/ruby/profiler/AddressProfiler.cc index 3f6b48956..9ff10dc90 100644 --- a/src/mem/ruby/profiler/AddressProfiler.cc +++ b/src/mem/ruby/profiler/AddressProfiler.cc @@ -67,9 +67,16 @@ AddressProfiler::~AddressProfiler() delete m_persistentPredictionProfileMap; } +void AddressProfiler::setHotLines(bool hot_lines){ + m_hot_lines = hot_lines; +} +void AddressProfiler::setAllInstructions(bool all_instructions){ + m_all_instructions = all_instructions; +} + void AddressProfiler::printStats(ostream& out) const { - if (PROFILE_HOT_LINES) { + if (m_hot_lines) { out << endl; out << "AddressProfiler Stats" << endl; out << "---------------------" << endl; @@ -97,7 +104,7 @@ void AddressProfiler::printStats(ostream& out) const printSorted(out, m_programCounterAccessTrace, "pc_address"); } - if (PROFILE_ALL_INSTRUCTIONS){ + if (m_all_instructions){ out << endl; out << "All Instructions Profile:" << endl; out << "-------------------------" << endl; @@ -189,7 +196,7 @@ void AddressProfiler::profileGetS(const Address& datablock, const Address& PC, c void AddressProfiler::addTraceSample(Address data_addr, Address pc_addr, CacheRequestType type, AccessModeType access_mode, NodeID id, bool sharing_miss) { - if (PROFILE_HOT_LINES) { + if (m_all_instructions) { if (sharing_miss) { m_sharing_miss_counter++; } @@ -206,7 +213,7 @@ void AddressProfiler::addTraceSample(Address data_addr, Address pc_addr, CacheRe lookupTraceForAddress(pc_addr, m_programCounterAccessTrace).update(type, access_mode, id, sharing_miss); } - if (PROFILE_ALL_INSTRUCTIONS) { + if (m_all_instructions) { // This code is used if the address profiler is an all-instructions profiler // record program counter address trace info lookupTraceForAddress(pc_addr, m_programCounterAccessTrace).update(type, access_mode, id, sharing_miss); @@ -248,7 +255,7 @@ static void printSorted(ostream& out, const Map* } out << "Total_entries_" << description << ": " << keys.size() << endl; - if (PROFILE_ALL_INSTRUCTIONS) + if (g_system_ptr->getProfiler()->getAllInstructions()) out << "Total_Instructions_" << description << ": " << misses << endl; else out << "Total_data_misses_" << description << ": " << misses << endl; @@ -263,8 +270,8 @@ static void printSorted(ostream& out, const Map* // Allows us to track how many lines where touched by n processors Vector m_touched_vec; Vector m_touched_weighted_vec; - m_touched_vec.setSize(RubyConfig::numberOfProcessors()+1); - m_touched_weighted_vec.setSize(RubyConfig::numberOfProcessors()+1); + m_touched_vec.setSize(RubySystem::getNumberOfSequencers()+1); + m_touched_weighted_vec.setSize(RubySystem::getNumberOfSequencers()+1); for (int i=0; i; m_L1D_cache_profiler_ptr = new CacheProfiler("L1D_cache"); m_L1I_cache_profiler_ptr = new CacheProfiler("L1I_cache"); m_L2_cache_profiler_ptr = new CacheProfiler("L2_cache"); + m_inst_profiler_ptr = NULL; + m_address_profiler_ptr = NULL; + +/* m_address_profiler_ptr = new AddressProfiler; m_inst_profiler_ptr = NULL; - if (PROFILE_ALL_INSTRUCTIONS) { + if (m_all_instructions) { m_inst_profiler_ptr = new AddressProfiler; } - +*/ m_conflicting_map_ptr = new Map; m_real_time_start_time = time(NULL); // Not reset in clearStats() m_stats_period = 1000000; // Default m_periodic_output_file_ptr = &cerr; +//changed by SS +/* // for MemoryControl: m_memReq = 0; m_memBankBusy = 0; @@ -116,8 +122,7 @@ Profiler::Profiler() * RubyConfig::ranksPerDimm() * RubyConfig::dimmsPerChannel(); m_memBankCount.setSize(totalBanks); - - clearStats(); +*/ } Profiler::~Profiler() @@ -133,32 +138,97 @@ Profiler::~Profiler() delete m_conflicting_map_ptr; } +void Profiler::init(const vector & argv, vector memory_control_names) +{ + // added by SS + vector::iterator it; + memory_control_profiler* mcp; + m_memory_control_names = memory_control_names; +// printf ( "Here in Profiler::init \n"); + for ( it=memory_control_names.begin() ; it < memory_control_names.end(); it++ ){ +// printf ( "Here in Profiler::init memory control name %s \n", (*it).c_str()); + mcp = new memory_control_profiler; + mcp->m_memReq = 0; + mcp->m_memBankBusy = 0; + mcp->m_memBusBusy = 0; + mcp->m_memReadWriteBusy = 0; + mcp->m_memDataBusBusy = 0; + mcp->m_memTfawBusy = 0; + mcp->m_memRefresh = 0; + mcp->m_memRead = 0; + mcp->m_memWrite = 0; + mcp->m_memWaitCycles = 0; + mcp->m_memInputQ = 0; + mcp->m_memBankQ = 0; + mcp->m_memArbWait = 0; + mcp->m_memRandBusy = 0; + mcp->m_memNotOld = 0; + + mcp->m_banks_per_rank = RubySystem::getMemoryControl((*it).c_str())->getBanksPerRank(); + mcp->m_ranks_per_dimm = RubySystem::getMemoryControl((*it).c_str())->getRanksPerDimm(); + mcp->m_dimms_per_channel = RubySystem::getMemoryControl((*it).c_str())->getDimmsPerChannel(); + + int totalBanks = mcp->m_banks_per_rank + * mcp->m_ranks_per_dimm + * mcp->m_dimms_per_channel; + + mcp->m_memBankCount.setSize(totalBanks); + + m_memory_control_profilers [(*it).c_str()] = mcp; + } + + clearStats(); + m_hot_lines = false; + m_all_instructions = false; + + for (size_t i=0; i setHotLines(m_hot_lines); + m_address_profiler_ptr -> setAllInstructions(m_all_instructions); + + if (m_all_instructions) { + m_inst_profiler_ptr = new AddressProfiler; + m_inst_profiler_ptr -> setHotLines(m_hot_lines); + m_inst_profiler_ptr -> setAllInstructions(m_all_instructions); + } +} + void Profiler::wakeup() { // FIXME - avoid the repeated code Vector perProcInstructionCount; - perProcInstructionCount.setSize(RubyConfig::numberOfProcessors()); + perProcInstructionCount.setSize(RubySystem::getNumberOfSequencers()); Vector perProcCycleCount; - perProcCycleCount.setSize(RubyConfig::numberOfProcessors()); + perProcCycleCount.setSize(RubySystem::getNumberOfSequencers()); - for(int i=0; i < RubyConfig::numberOfProcessors(); i++) { - perProcInstructionCount[i] = g_system_ptr->getDriver()->getInstructionCount(i) - m_instructions_executed_at_start[i] + 1; - perProcCycleCount[i] = g_system_ptr->getDriver()->getCycleCount(i) - m_cycles_executed_at_start[i] + 1; + for(int i=0; i < RubySystem::getNumberOfSequencers(); i++) { + perProcInstructionCount[i] = g_system_ptr->getInstructionCount(i) - m_instructions_executed_at_start[i] + 1; + perProcCycleCount[i] = g_system_ptr->getCycleCount(i) - m_cycles_executed_at_start[i] + 1; // The +1 allows us to avoid division by zero } integer_t total_misses = m_perProcTotalMisses.sum(); integer_t instruction_executed = perProcInstructionCount.sum(); - integer_t cycles_executed = perProcCycleCount.sum(); + integer_t simics_cycles_executed = perProcCycleCount.sum(); integer_t transactions_started = m_perProcStartTransaction.sum(); integer_t transactions_ended = m_perProcEndTransaction.sum(); (*m_periodic_output_file_ptr) << "ruby_cycles: " << g_eventQueue_ptr->getTime()-m_ruby_start << endl; (*m_periodic_output_file_ptr) << "total_misses: " << total_misses << " " << m_perProcTotalMisses << endl; (*m_periodic_output_file_ptr) << "instruction_executed: " << instruction_executed << " " << perProcInstructionCount << endl; - (*m_periodic_output_file_ptr) << "cycles_executed: " << cycles_executed << " " << perProcCycleCount << endl; + (*m_periodic_output_file_ptr) << "simics_cycles_executed: " << simics_cycles_executed << " " << perProcCycleCount << endl; (*m_periodic_output_file_ptr) << "transactions_started: " << transactions_started << " " << m_perProcStartTransaction << endl; (*m_periodic_output_file_ptr) << "transactions_ended: " << transactions_ended << " " << m_perProcEndTransaction << endl; (*m_periodic_output_file_ptr) << "L1TBE_usage: " << m_L1tbeProfile << endl; @@ -172,7 +242,7 @@ void Profiler::wakeup() *m_periodic_output_file_ptr << endl; - if (PROFILE_ALL_INSTRUCTIONS) { + if (m_all_instructions) { m_inst_profiler_ptr->printStats(*m_periodic_output_file_ptr); } @@ -277,18 +347,18 @@ void Profiler::printStats(ostream& out, bool short_stats) Vector perProcCyclesPerTrans; Vector perProcMissesPerTrans; - perProcInstructionCount.setSize(RubyConfig::numberOfProcessors()); - perProcCycleCount.setSize(RubyConfig::numberOfProcessors()); - perProcCPI.setSize(RubyConfig::numberOfProcessors()); - perProcMissesPerInsn.setSize(RubyConfig::numberOfProcessors()); + perProcInstructionCount.setSize(RubySystem::getNumberOfSequencers()); + perProcCycleCount.setSize(RubySystem::getNumberOfSequencers()); + perProcCPI.setSize(RubySystem::getNumberOfSequencers()); + perProcMissesPerInsn.setSize(RubySystem::getNumberOfSequencers()); - perProcInsnPerTrans.setSize(RubyConfig::numberOfProcessors()); - perProcCyclesPerTrans.setSize(RubyConfig::numberOfProcessors()); - perProcMissesPerTrans.setSize(RubyConfig::numberOfProcessors()); + perProcInsnPerTrans.setSize(RubySystem::getNumberOfSequencers()); + perProcCyclesPerTrans.setSize(RubySystem::getNumberOfSequencers()); + perProcMissesPerTrans.setSize(RubySystem::getNumberOfSequencers()); - for(int i=0; i < RubyConfig::numberOfProcessors(); i++) { - perProcInstructionCount[i] = g_system_ptr->getDriver()->getInstructionCount(i) - m_instructions_executed_at_start[i] + 1; - perProcCycleCount[i] = g_system_ptr->getDriver()->getCycleCount(i) - m_cycles_executed_at_start[i] + 1; + for(int i=0; i < RubySystem::getNumberOfSequencers(); i++) { + perProcInstructionCount[i] = g_system_ptr->getInstructionCount(i) - m_instructions_executed_at_start[i] + 1; + perProcCycleCount[i] = g_system_ptr->getCycleCount(i) - m_cycles_executed_at_start[i] + 1; // The +1 allows us to avoid division by zero perProcCPI[i] = double(ruby_cycles)/perProcInstructionCount[i]; perProcMissesPerInsn[i] = 1000.0 * (double(m_perProcTotalMisses[i]) / double(perProcInstructionCount[i])); @@ -309,12 +379,12 @@ void Profiler::printStats(ostream& out, bool short_stats) integer_t user_misses = m_perProcUserMisses.sum(); integer_t supervisor_misses = m_perProcSupervisorMisses.sum(); integer_t instruction_executed = perProcInstructionCount.sum(); - integer_t cycles_executed = perProcCycleCount.sum(); + integer_t simics_cycles_executed = perProcCycleCount.sum(); integer_t transactions_started = m_perProcStartTransaction.sum(); integer_t transactions_ended = m_perProcEndTransaction.sum(); double instructions_per_transaction = (transactions_ended != 0) ? double(instruction_executed) / double(transactions_ended) : 0; - double cycles_per_transaction = (transactions_ended != 0) ? (RubyConfig::numberOfProcessors() * double(ruby_cycles)) / double(transactions_ended) : 0; + double cycles_per_transaction = (transactions_ended != 0) ? (RubySystem::getNumberOfSequencers() * double(ruby_cycles)) / double(transactions_ended) : 0; double misses_per_transaction = (transactions_ended != 0) ? double(total_misses) / double(transactions_ended) : 0; out << "Total_misses: " << total_misses << endl; @@ -323,8 +393,8 @@ void Profiler::printStats(ostream& out, bool short_stats) out << "supervisor_misses: " << supervisor_misses << " " << m_perProcSupervisorMisses << endl; out << endl; out << "instruction_executed: " << instruction_executed << " " << perProcInstructionCount << endl; - out << "cycles_executed: " << cycles_executed << " " << perProcCycleCount << endl; - out << "cycles_per_instruction: " << (RubyConfig::numberOfProcessors()*double(ruby_cycles))/double(instruction_executed) << " " << perProcCPI << endl; + out << "ruby_cycles_executed: " << simics_cycles_executed << " " << perProcCycleCount << endl; + out << "cycles_per_instruction: " << (RubySystem::getNumberOfSequencers()*double(ruby_cycles))/double(instruction_executed) << " " << perProcCPI << endl; out << "misses_per_thousand_instructions: " << 1000.0 * (double(total_misses) / double(instruction_executed)) << " " << perProcMissesPerInsn << endl; out << endl; out << "transactions_started: " << transactions_started << " " << m_perProcStartTransaction << endl; @@ -341,44 +411,64 @@ void Profiler::printStats(ostream& out, bool short_stats) out << endl; - if (m_memReq || m_memRefresh) { // if there's a memory controller at all - long long int total_stalls = m_memInputQ + m_memBankQ + m_memWaitCycles; - double stallsPerReq = total_stalls * 1.0 / m_memReq; - out << "Memory control:" << endl; - out << " memory_total_requests: " << m_memReq << endl; // does not include refreshes - out << " memory_reads: " << m_memRead << endl; - out << " memory_writes: " << m_memWrite << endl; - out << " memory_refreshes: " << m_memRefresh << endl; - out << " memory_total_request_delays: " << total_stalls << endl; - out << " memory_delays_per_request: " << stallsPerReq << endl; - out << " memory_delays_in_input_queue: " << m_memInputQ << endl; - out << " memory_delays_behind_head_of_bank_queue: " << m_memBankQ << endl; - out << " memory_delays_stalled_at_head_of_bank_queue: " << m_memWaitCycles << endl; - // Note: The following "memory stalls" entries are a breakdown of the - // cycles which already showed up in m_memWaitCycles. The order is - // significant; it is the priority of attributing the cycles. - // For example, bank_busy is before arbitration because if the bank was - // busy, we didn't even check arbitration. - // Note: "not old enough" means that since we grouped waiting heads-of-queues - // into batches to avoid starvation, a request in a newer batch - // didn't try to arbitrate yet because there are older requests waiting. - out << " memory_stalls_for_bank_busy: " << m_memBankBusy << endl; - out << " memory_stalls_for_random_busy: " << m_memRandBusy << endl; - out << " memory_stalls_for_anti_starvation: " << m_memNotOld << endl; - out << " memory_stalls_for_arbitration: " << m_memArbWait << endl; - out << " memory_stalls_for_bus: " << m_memBusBusy << endl; - out << " memory_stalls_for_tfaw: " << m_memTfawBusy << endl; - out << " memory_stalls_for_read_write_turnaround: " << m_memReadWriteBusy << endl; - out << " memory_stalls_for_read_read_turnaround: " << m_memDataBusBusy << endl; - out << " accesses_per_bank: "; - for (int bank=0; bank < m_memBankCount.size(); bank++) { - out << m_memBankCount[bank] << " "; - //if ((bank % 8) == 7) out << " " << endl; + vector::iterator it; + + for ( it=m_memory_control_names.begin() ; it < m_memory_control_names.end(); it++ ){ + long long int m_memReq = m_memory_control_profilers[(*it).c_str()] -> m_memReq; + long long int m_memRefresh = m_memory_control_profilers[(*it).c_str()] -> m_memRefresh; + long long int m_memInputQ = m_memory_control_profilers[(*it).c_str()] -> m_memInputQ; + long long int m_memBankQ = m_memory_control_profilers[(*it).c_str()] -> m_memBankQ; + long long int m_memWaitCycles = m_memory_control_profilers[(*it).c_str()] -> m_memWaitCycles; + long long int m_memRead = m_memory_control_profilers[(*it).c_str()] -> m_memRead; + long long int m_memWrite = m_memory_control_profilers[(*it).c_str()] -> m_memWrite; + long long int m_memBankBusy = m_memory_control_profilers[(*it).c_str()] -> m_memBankBusy; + long long int m_memRandBusy = m_memory_control_profilers[(*it).c_str()] -> m_memRandBusy; + long long int m_memNotOld = m_memory_control_profilers[(*it).c_str()] -> m_memNotOld; + long long int m_memArbWait = m_memory_control_profilers[(*it).c_str()] -> m_memArbWait; + long long int m_memBusBusy = m_memory_control_profilers[(*it).c_str()] -> m_memBusBusy; + long long int m_memTfawBusy = m_memory_control_profilers[(*it).c_str()] -> m_memTfawBusy; + long long int m_memReadWriteBusy = m_memory_control_profilers[(*it).c_str()] -> m_memReadWriteBusy; + long long int m_memDataBusBusy = m_memory_control_profilers[(*it).c_str()] -> m_memDataBusBusy; + Vector m_memBankCount = m_memory_control_profilers[(*it).c_str()] -> m_memBankCount; + + if (m_memReq || m_memRefresh) { // if there's a memory controller at all + long long int total_stalls = m_memInputQ + m_memBankQ + m_memWaitCycles; + double stallsPerReq = total_stalls * 1.0 / m_memReq; + out << "Memory control:" << endl; + out << " memory_total_requests: " << m_memReq << endl; // does not include refreshes + out << " memory_reads: " << m_memRead << endl; + out << " memory_writes: " << m_memWrite << endl; + out << " memory_refreshes: " << m_memRefresh << endl; + out << " memory_total_request_delays: " << total_stalls << endl; + out << " memory_delays_per_request: " << stallsPerReq << endl; + out << " memory_delays_in_input_queue: " << m_memInputQ << endl; + out << " memory_delays_behind_head_of_bank_queue: " << m_memBankQ << endl; + out << " memory_delays_stalled_at_head_of_bank_queue: " << m_memWaitCycles << endl; + // Note: The following "memory stalls" entries are a breakdown of the + // cycles which already showed up in m_memWaitCycles. The order is + // significant; it is the priority of attributing the cycles. + // For example, bank_busy is before arbitration because if the bank was + // busy, we didn't even check arbitration. + // Note: "not old enough" means that since we grouped waiting heads-of-queues + // into batches to avoid starvation, a request in a newer batch + // didn't try to arbitrate yet because there are older requests waiting. + out << " memory_stalls_for_bank_busy: " << m_memBankBusy << endl; + out << " memory_stalls_for_random_busy: " << m_memRandBusy << endl; + out << " memory_stalls_for_anti_starvation: " << m_memNotOld << endl; + out << " memory_stalls_for_arbitration: " << m_memArbWait << endl; + out << " memory_stalls_for_bus: " << m_memBusBusy << endl; + out << " memory_stalls_for_tfaw: " << m_memTfawBusy << endl; + out << " memory_stalls_for_read_write_turnaround: " << m_memReadWriteBusy << endl; + out << " memory_stalls_for_read_read_turnaround: " << m_memDataBusBusy << endl; + out << " accesses_per_bank: "; + for (int bank=0; bank < m_memBankCount.size(); bank++) { + out << m_memBankCount[bank] << " "; + //if ((bank % 8) == 7) out << " " << endl; + } + out << endl; + out << endl; } - out << endl; - out << endl; } - if (!short_stats) { out << "Busy Controller Counts:" << endl; for(int i=0; i < MachineType_NUM; i++) { @@ -413,7 +503,7 @@ void Profiler::printStats(ostream& out, bool short_stats) out << "miss_latency: " << m_allMissLatencyHistogram << endl; for(int i=0; i 0) { - out << "miss_latency_" << CacheRequestType(i) << ": " << m_missLatencyHistograms[i] << endl; + out << "miss_latency_" << RubyRequestType(i) << ": " << m_missLatencyHistograms[i] << endl; } } for(int i=0; iprintStats(out); } - if (PROFILE_ALL_INSTRUCTIONS) { + if (m_all_instructions) { m_inst_profiler_ptr->printStats(out); } @@ -550,25 +640,25 @@ void Profiler::clearStats() m_ruby_start = g_eventQueue_ptr->getTime(); - m_instructions_executed_at_start.setSize(RubyConfig::numberOfProcessors()); - m_cycles_executed_at_start.setSize(RubyConfig::numberOfProcessors()); - for (int i=0; i < RubyConfig::numberOfProcessors(); i++) { + m_instructions_executed_at_start.setSize(RubySystem::getNumberOfSequencers()); + m_cycles_executed_at_start.setSize(RubySystem::getNumberOfSequencers()); + for (int i=0; i < RubySystem::getNumberOfSequencers(); i++) { if (g_system_ptr == NULL) { m_instructions_executed_at_start[i] = 0; m_cycles_executed_at_start[i] = 0; } else { - m_instructions_executed_at_start[i] = g_system_ptr->getDriver()->getInstructionCount(i); - m_cycles_executed_at_start[i] = g_system_ptr->getDriver()->getCycleCount(i); + m_instructions_executed_at_start[i] = g_system_ptr->getInstructionCount(i); + m_cycles_executed_at_start[i] = g_system_ptr->getCycleCount(i); } } - m_perProcTotalMisses.setSize(RubyConfig::numberOfProcessors()); - m_perProcUserMisses.setSize(RubyConfig::numberOfProcessors()); - m_perProcSupervisorMisses.setSize(RubyConfig::numberOfProcessors()); - m_perProcStartTransaction.setSize(RubyConfig::numberOfProcessors()); - m_perProcEndTransaction.setSize(RubyConfig::numberOfProcessors()); + m_perProcTotalMisses.setSize(RubySystem::getNumberOfSequencers()); + m_perProcUserMisses.setSize(RubySystem::getNumberOfSequencers()); + m_perProcSupervisorMisses.setSize(RubySystem::getNumberOfSequencers()); + m_perProcStartTransaction.setSize(RubySystem::getNumberOfSequencers()); + m_perProcEndTransaction.setSize(RubySystem::getNumberOfSequencers()); - for(int i=0; i < RubyConfig::numberOfProcessors(); i++) { + for(int i=0; i < RubySystem::getNumberOfSequencers(); i++) { m_perProcTotalMisses[i] = 0; m_perProcUserMisses[i] = 0; m_perProcSupervisorMisses[i] = 0; @@ -587,8 +677,8 @@ void Profiler::clearStats() m_delayedCyclesHistogram.clear(); m_delayedCyclesNonPFHistogram.clear(); - m_delayedCyclesVCHistograms.setSize(NUMBER_OF_VIRTUAL_NETWORKS); - for (int i = 0; i < NUMBER_OF_VIRTUAL_NETWORKS; i++) { + m_delayedCyclesVCHistograms.setSize(RubySystem::getNetwork()->getNumberOfVirtualNetworks()); + for (int i = 0; i < RubySystem::getNetwork()->getNumberOfVirtualNetworks(); i++) { m_delayedCyclesVCHistograms[i].clear(); } @@ -656,6 +746,7 @@ void Profiler::clearStats() m_L2_cache_profiler_ptr->clearStats(); // for MemoryControl: +/* m_memReq = 0; m_memBankBusy = 0; m_memBusBusy = 0; @@ -675,7 +766,31 @@ void Profiler::clearStats() for (int bank=0; bank < m_memBankCount.size(); bank++) { m_memBankCount[bank] = 0; } - +*/ +//added by SS + vector::iterator it; + + for ( it=m_memory_control_names.begin() ; it < m_memory_control_names.end(); it++ ){ + m_memory_control_profilers[(*it).c_str()] -> m_memReq = 0; + m_memory_control_profilers[(*it).c_str()] -> m_memBankBusy = 0; + m_memory_control_profilers[(*it).c_str()] -> m_memBusBusy = 0; + m_memory_control_profilers[(*it).c_str()] -> m_memTfawBusy = 0; + m_memory_control_profilers[(*it).c_str()] -> m_memReadWriteBusy = 0; + m_memory_control_profilers[(*it).c_str()] -> m_memDataBusBusy = 0; + m_memory_control_profilers[(*it).c_str()] -> m_memRefresh = 0; + m_memory_control_profilers[(*it).c_str()] -> m_memRead = 0; + m_memory_control_profilers[(*it).c_str()] -> m_memWrite = 0; + m_memory_control_profilers[(*it).c_str()] -> m_memWaitCycles = 0; + m_memory_control_profilers[(*it).c_str()] -> m_memInputQ = 0; + m_memory_control_profilers[(*it).c_str()] -> m_memBankQ = 0; + m_memory_control_profilers[(*it).c_str()] -> m_memArbWait = 0; + m_memory_control_profilers[(*it).c_str()] -> m_memRandBusy = 0; + m_memory_control_profilers[(*it).c_str()] -> m_memNotOld = 0; + + for (int bank=0; bank < m_memory_control_profilers[(*it).c_str()] -> m_memBankCount.size(); bank++) { + m_memory_control_profilers[(*it).c_str()] -> m_memBankCount[bank] = 0; + } + } // Flush the prefetches through the system - used so that there are no outstanding requests after stats are cleared //g_eventQueue_ptr->triggerAllEvents(); @@ -707,7 +822,7 @@ void Profiler::profileConflictingRequests(const Address& addr) assert(addr == line_address(addr)); Time last_time = m_ruby_start; if (m_conflicting_map_ptr->exist(addr)) { - last_time = m_conflicting_map_ptr->lookup(addr); + Time last_time = m_conflicting_map_ptr->lookup(addr); } Time current_time = g_eventQueue_ptr->getTime(); assert (current_time - last_time > 0); @@ -755,8 +870,8 @@ void Profiler::addAddressTraceSample(const CacheMsg& msg, NodeID id) // Note: The following line should be commented out if you want to // use the special profiling that is part of the GS320 protocol - // NOTE: Unless PROFILE_HOT_LINES or PROFILE_ALL_INSTRUCTIONS are enabled, nothing will be profiled by the AddressProfiler - m_address_profiler_ptr->addTraceSample(msg.getAddress(), msg.getProgramCounter(), msg.getType(), msg.getAccessMode(), id, false); + // NOTE: Unless PROFILE_HOT_LINES or RubyConfig::getProfileAllInstructions() are enabled, nothing will be profiled by the AddressProfiler + m_address_profiler_ptr->addTraceSample(msg.getLineAddress(), msg.getProgramCounter(), msg.getType(), msg.getAccessMode(), id, false); } } @@ -852,14 +967,16 @@ void Profiler::bankBusy() } // non-zero cycle demand request -void Profiler::missLatency(Time t, CacheRequestType type, GenericMachineType respondingMach) +void Profiler::missLatency(Time t, RubyRequestType type) { m_allMissLatencyHistogram.add(t); m_missLatencyHistograms[type].add(t); + /* m_machLatencyHistograms[respondingMach].add(t); if(respondingMach == GenericMachineType_Directory || respondingMach == GenericMachineType_NUM) { m_L2MissLatencyHistogram.add(t); } + */ } // non-zero cycle prefetch request @@ -873,7 +990,7 @@ void Profiler::swPrefetchLatency(Time t, CacheRequestType type, GenericMachineTy } } -void Profiler::profileTransition(const string& component, NodeID id, NodeID version, Address addr, +void Profiler::profileTransition(const string& component, NodeID version, Address addr, const string& state, const string& event, const string& next_state, const string& note) { @@ -887,22 +1004,16 @@ void Profiler::profileTransition(const string& component, NodeID id, NodeID vers (g_eventQueue_ptr->getTime() >= g_debug_ptr->getDebugTime())) { (* debug_cout_ptr).flags(ios::right); (* debug_cout_ptr) << setw(TIME_SPACES) << g_eventQueue_ptr->getTime() << " "; - (* debug_cout_ptr) << setw(ID_SPACES) << id << " "; (* debug_cout_ptr) << setw(ID_SPACES) << version << " "; (* debug_cout_ptr) << setw(COMP_SPACES) << component; (* debug_cout_ptr) << setw(EVENT_SPACES) << event << " "; - for (int i=0; i < RubyConfig::numberOfProcessors(); i++) { - - if (i == id) { - (* debug_cout_ptr).flags(ios::right); - (* debug_cout_ptr) << setw(STATE_SPACES) << state; - (* debug_cout_ptr) << ">"; - (* debug_cout_ptr).flags(ios::left); - (* debug_cout_ptr) << setw(STATE_SPACES) << next_state; - } else { - // cout << setw(STATE_SPACES) << " " << " " << setw(STATE_SPACES) << " "; - } - } + + (* debug_cout_ptr).flags(ios::right); + (* debug_cout_ptr) << setw(STATE_SPACES) << state; + (* debug_cout_ptr) << ">"; + (* debug_cout_ptr).flags(ios::left); + (* debug_cout_ptr) << setw(STATE_SPACES) << next_state; + (* debug_cout_ptr) << " " << addr << " " << note; (* debug_cout_ptr) << endl; @@ -949,32 +1060,11 @@ void Profiler::profileTrainingMask(const Set& pred_set) m_explicit_training_mask.add(pred_set.count()); } -// For MemoryControl: -void Profiler::profileMemReq(int bank) { - m_memReq++; - m_memBankCount[bank]++; -} - -void Profiler::profileMemBankBusy() { m_memBankBusy++; } -void Profiler::profileMemBusBusy() { m_memBusBusy++; } -void Profiler::profileMemReadWriteBusy() { m_memReadWriteBusy++; } -void Profiler::profileMemDataBusBusy() { m_memDataBusBusy++; } -void Profiler::profileMemTfawBusy() { m_memTfawBusy++; } -void Profiler::profileMemRefresh() { m_memRefresh++; } -void Profiler::profileMemRead() { m_memRead++; } -void Profiler::profileMemWrite() { m_memWrite++; } -void Profiler::profileMemWaitCycles(int cycles) { m_memWaitCycles += cycles; } -void Profiler::profileMemInputQ(int cycles) { m_memInputQ += cycles; } -void Profiler::profileMemBankQ(int cycles) { m_memBankQ += cycles; } -void Profiler::profileMemArbWait(int cycles) { m_memArbWait += cycles; } -void Profiler::profileMemRandBusy() { m_memRandBusy++; } -void Profiler::profileMemNotOld() { m_memNotOld++; } - int64 Profiler::getTotalInstructionsExecuted() const { int64 sum = 1; // Starting at 1 allows us to avoid division by zero - for(int i=0; i < RubyConfig::numberOfProcessors(); i++) { - sum += (g_system_ptr->getDriver()->getInstructionCount(i) - m_instructions_executed_at_start[i]); + for(int i=0; i < RubySystem::getNumberOfSequencers(); i++) { + sum += (g_system_ptr->getInstructionCount(i) - m_instructions_executed_at_start[i]); } return sum; } @@ -1014,3 +1104,51 @@ GenericRequestType Profiler::CacheRequestType_to_GenericRequestType(const CacheR } } +void Profiler::rubyWatch(int id){ + int rn_g1 = 0;//SIMICS_get_register_number(id, "g1"); + uint64 tr = 0;//SIMICS_read_register(id, rn_g1); + Address watch_address = Address(tr); + const int ID_SPACES = 3; + const int TIME_SPACES = 7; + + (* debug_cout_ptr).flags(ios::right); + (* debug_cout_ptr) << setw(TIME_SPACES) << g_eventQueue_ptr->getTime() << " "; + (* debug_cout_ptr) << setw(ID_SPACES) << id << " " + << "RUBY WATCH " + << watch_address + << endl; + + if(!m_watch_address_list_ptr->exist(watch_address)){ + m_watch_address_list_ptr->add(watch_address, 1); + } +} + +bool Profiler::watchAddress(Address addr){ + if (m_watch_address_list_ptr->exist(addr)) + return true; + else + return false; +} + +// For MemoryControl: +void Profiler::profileMemReq(string name, int bank) { +// printf("name is %s", name.c_str()); + assert(m_memory_control_profilers.count(name) == 1); + m_memory_control_profilers[name] -> m_memReq++; + m_memory_control_profilers[name] -> m_memBankCount[bank]++; +} +void Profiler::profileMemBankBusy(string name) { assert(m_memory_control_profilers.count(name) == 1); m_memory_control_profilers[name] -> m_memBankBusy++; } +void Profiler::profileMemBusBusy(string name) { assert(m_memory_control_profilers.count(name) == 1); m_memory_control_profilers[name] -> m_memBusBusy++; } +void Profiler::profileMemReadWriteBusy(string name) { assert(m_memory_control_profilers.count(name) == 1); m_memory_control_profilers[name] -> m_memReadWriteBusy++; } +void Profiler::profileMemDataBusBusy(string name) { assert(m_memory_control_profilers.count(name) == 1); m_memory_control_profilers[name] -> m_memDataBusBusy++; } +void Profiler::profileMemTfawBusy(string name) { assert(m_memory_control_profilers.count(name) == 1); m_memory_control_profilers[name] -> m_memTfawBusy++; } +void Profiler::profileMemRefresh(string name) { assert(m_memory_control_profilers.count(name) == 1); m_memory_control_profilers[name] -> m_memRefresh++; } +void Profiler::profileMemRead(string name) { assert(m_memory_control_profilers.count(name) == 1); m_memory_control_profilers[name] -> m_memRead++; } +void Profiler::profileMemWrite(string name) { assert(m_memory_control_profilers.count(name) == 1); m_memory_control_profilers[name] -> m_memWrite++; } +void Profiler::profileMemWaitCycles(string name, int cycles) { assert(m_memory_control_profilers.count(name) == 1); m_memory_control_profilers[name] -> m_memWaitCycles += cycles; } +void Profiler::profileMemInputQ(string name, int cycles) { assert(m_memory_control_profilers.count(name) == 1); m_memory_control_profilers[name] -> m_memInputQ += cycles; } +void Profiler::profileMemBankQ(string name, int cycles) { assert(m_memory_control_profilers.count(name) == 1); m_memory_control_profilers[name] -> m_memBankQ += cycles; } +void Profiler::profileMemArbWait(string name, int cycles) { assert(m_memory_control_profilers.count(name) == 1); m_memory_control_profilers[name] -> m_memArbWait += cycles; } +void Profiler::profileMemRandBusy(string name) { assert(m_memory_control_profilers.count(name) == 1); m_memory_control_profilers[name] -> m_memRandBusy++; } +void Profiler::profileMemNotOld(string name) { assert(m_memory_control_profilers.count(name) == 1); m_memory_control_profilers[name] -> m_memNotOld++; } + diff --git a/src/mem/ruby/profiler/Profiler.hh b/src/mem/ruby/profiler/Profiler.hh index e25105982..4731c7138 100644 --- a/src/mem/ruby/profiler/Profiler.hh +++ b/src/mem/ruby/profiler/Profiler.hh @@ -54,6 +54,8 @@ #ifndef PROFILER_H #define PROFILER_H +#include "mem/ruby/libruby.hh" + #include "mem/ruby/common/Global.hh" #include "mem/protocol/GenericMachineType.hh" #include "mem/ruby/config/RubyConfig.hh" @@ -68,6 +70,7 @@ #include "mem/ruby/common/Set.hh" #include "mem/protocol/CacheRequestType.hh" #include "mem/protocol/GenericRequestType.hh" +#include "mem/ruby/system/MemoryControl.hh" class CacheMsg; class CacheProfiler; @@ -75,231 +78,236 @@ class AddressProfiler; template class Map; +struct memory_control_profiler { + long long int m_memReq; + long long int m_memBankBusy; + long long int m_memBusBusy; + long long int m_memTfawBusy; + long long int m_memReadWriteBusy; + long long int m_memDataBusBusy; + long long int m_memRefresh; + long long int m_memRead; + long long int m_memWrite; + long long int m_memWaitCycles; + long long int m_memInputQ; + long long int m_memBankQ; + long long int m_memArbWait; + long long int m_memRandBusy; + long long int m_memNotOld; + Vector m_memBankCount; + int m_banks_per_rank; + int m_ranks_per_dimm; + int m_dimms_per_channel; +}; + + class Profiler : public Consumer { public: - // Constructors - Profiler(); - - // Destructor - ~Profiler(); - - // Public Methods - void wakeup(); - - void setPeriodicStatsFile(const string& filename); - void setPeriodicStatsInterval(integer_t period); - - void printStats(ostream& out, bool short_stats=false); - void printShortStats(ostream& out) { printStats(out, true); } - void printTraceStats(ostream& out) const; - void clearStats(); - void printConfig(ostream& out) const; - void printResourceUsage(ostream& out) const; - - AddressProfiler* getAddressProfiler() { return m_address_profiler_ptr; } - AddressProfiler* getInstructionProfiler() { return m_inst_profiler_ptr; } - - void addPrimaryStatSample(const CacheMsg& msg, NodeID id); - void addSecondaryStatSample(GenericRequestType requestType, - AccessModeType type, int msgSize, - PrefetchBit pfBit, NodeID id); - void addSecondaryStatSample(CacheRequestType requestType, - AccessModeType type, int msgSize, - PrefetchBit pfBit, NodeID id); - void addAddressTraceSample(const CacheMsg& msg, NodeID id); - - void profileRequest(const string& requestStr); - void profileSharing(const Address& addr, AccessType type, - NodeID requestor, const Set& sharers, - const Set& owner); - - void profileMulticastRetry(const Address& addr, int count); - - void profileFilterAction(int action); - - void profileConflictingRequests(const Address& addr); - void profileOutstandingRequest(int outstanding) { - m_outstanding_requests.add(outstanding); - } - - void profileOutstandingPersistentRequest(int outstanding) { - m_outstanding_persistent_requests.add(outstanding); - } - void profileAverageLatencyEstimate(int latency) { - m_average_latency_estimate.add(latency); - } - - void countBAUnicast() { m_num_BA_unicasts++; } - void countBABroadcast() { m_num_BA_broadcasts++; } - - void recordPrediction(bool wasGood, bool wasPredicted); - - void startTransaction(int cpu); - void endTransaction(int cpu); - void profilePFWait(Time waitTime); - - void controllerBusy(MachineID machID); - void bankBusy(); - void missLatency(Time t, CacheRequestType type, - GenericMachineType respondingMach); - void swPrefetchLatency(Time t, CacheRequestType type, - GenericMachineType respondingMach); - void stopTableUsageSample(int num) { m_stopTableProfile.add(num); } - void L1tbeUsageSample(int num) { m_L1tbeProfile.add(num); } - void L2tbeUsageSample(int num) { m_L2tbeProfile.add(num); } - void sequencerRequests(int num) { m_sequencer_requests.add(num); } - void storeBuffer(int size, int blocks) { - m_store_buffer_size.add(size); - m_store_buffer_blocks.add(blocks); - } - - void profileGetXMaskPrediction(const Set& pred_set); - void profileGetSMaskPrediction(const Set& pred_set); - void profileTrainingMask(const Set& pred_set); - void profileTransition(const string& component, NodeID id, NodeID version, - Address addr, const string& state, - const string& event, const string& next_state, - const string& note); - void profileMsgDelay(int virtualNetwork, int delayCycles); - - void print(ostream& out) const; - - int64 getTotalInstructionsExecuted() const; - int64 getTotalTransactionsExecuted() const; - - Time getRubyStartTime(){ - return m_ruby_start; - } - - // added for MemoryControl: - void profileMemReq(int bank); - void profileMemBankBusy(); - void profileMemBusBusy(); - void profileMemTfawBusy(); - void profileMemReadWriteBusy(); - void profileMemDataBusBusy(); - void profileMemRefresh(); - void profileMemRead(); - void profileMemWrite(); - void profileMemWaitCycles(int cycles); - void profileMemInputQ(int cycles); - void profileMemBankQ(int cycles); - void profileMemArbWait(int cycles); - void profileMemRandBusy(); - void profileMemNotOld(); + // Constructors + Profiler(const string & name); + + void init(const vector & argv, vector memory_control_names); + + // Destructor + ~Profiler(); + + // Public Methods + void wakeup(); + + void setPeriodicStatsFile(const string& filename); + void setPeriodicStatsInterval(integer_t period); + + void printStats(ostream& out, bool short_stats=false); + void printShortStats(ostream& out) { printStats(out, true); } + void printTraceStats(ostream& out) const; + void clearStats(); + void printConfig(ostream& out) const; + void printResourceUsage(ostream& out) const; + + AddressProfiler* getAddressProfiler() { return m_address_profiler_ptr; } + AddressProfiler* getInstructionProfiler() { return m_inst_profiler_ptr; } + + void addPrimaryStatSample(const CacheMsg& msg, NodeID id); + void addSecondaryStatSample(GenericRequestType requestType, AccessModeType type, int msgSize, PrefetchBit pfBit, NodeID id); + void addSecondaryStatSample(CacheRequestType requestType, AccessModeType type, int msgSize, PrefetchBit pfBit, NodeID id); + void addAddressTraceSample(const CacheMsg& msg, NodeID id); + + void profileRequest(const string& requestStr); + void profileSharing(const Address& addr, AccessType type, NodeID requestor, const Set& sharers, const Set& owner); + + void profileMulticastRetry(const Address& addr, int count); + + void profileFilterAction(int action); + + void profileConflictingRequests(const Address& addr); + void profileOutstandingRequest(int outstanding) { m_outstanding_requests.add(outstanding); } + void profileOutstandingPersistentRequest(int outstanding) { m_outstanding_persistent_requests.add(outstanding); } + void profileAverageLatencyEstimate(int latency) { m_average_latency_estimate.add(latency); } + + void countBAUnicast() { m_num_BA_unicasts++; } + void countBABroadcast() { m_num_BA_broadcasts++; } + + void recordPrediction(bool wasGood, bool wasPredicted); + + void startTransaction(int cpu); + void endTransaction(int cpu); + void profilePFWait(Time waitTime); + + void controllerBusy(MachineID machID); + void bankBusy(); + void missLatency(Time t, RubyRequestType type); + void swPrefetchLatency(Time t, CacheRequestType type, GenericMachineType respondingMach); + void stopTableUsageSample(int num) { m_stopTableProfile.add(num); } + void L1tbeUsageSample(int num) { m_L1tbeProfile.add(num); } + void L2tbeUsageSample(int num) { m_L2tbeProfile.add(num); } + void sequencerRequests(int num) { m_sequencer_requests.add(num); } + void storeBuffer(int size, int blocks) { m_store_buffer_size.add(size); m_store_buffer_blocks.add(blocks);} + + void profileGetXMaskPrediction(const Set& pred_set); + void profileGetSMaskPrediction(const Set& pred_set); + void profileTrainingMask(const Set& pred_set); + void profileTransition(const string& component, NodeID version, Address addr, + const string& state, const string& event, + const string& next_state, const string& note); + void profileMsgDelay(int virtualNetwork, int delayCycles); + + void print(ostream& out) const; + + int64 getTotalInstructionsExecuted() const; + int64 getTotalTransactionsExecuted() const; + + void rubyWatch(int proc); + bool watchAddress(Address addr); + + // return Ruby's start time + Time getRubyStartTime(){ + return m_ruby_start; + } + + // added for MemoryControl: + void profileMemReq(string name, int bank); + void profileMemBankBusy(string name); + void profileMemBusBusy(string name); + void profileMemTfawBusy(string name); + void profileMemReadWriteBusy(string name); + void profileMemDataBusBusy(string name); + void profileMemRefresh(string name); + void profileMemRead(string name); + void profileMemWrite(string name); + void profileMemWaitCycles(string name, int cycles); + void profileMemInputQ(string name, int cycles); + void profileMemBankQ(string name, int cycles); + void profileMemArbWait(string name, int cycles); + void profileMemRandBusy(string name); + void profileMemNotOld(string name); + //added by SS + bool getHotLines() { return m_hot_lines; } + bool getAllInstructions() { return m_all_instructions; } private: - // Private Methods - void addL2StatSample(GenericRequestType requestType, AccessModeType type, - int msgSize, PrefetchBit pfBit, NodeID id); - void addL1DStatSample(const CacheMsg& msg, NodeID id); - void addL1IStatSample(const CacheMsg& msg, NodeID id); - - GenericRequestType CacheRequestType_to_GenericRequestType(const CacheRequestType& type); - - // Private copy constructor and assignment operator - Profiler(const Profiler& obj); - Profiler& operator=(const Profiler& obj); - - // Data Members (m_ prefix) - CacheProfiler* m_L1D_cache_profiler_ptr; - CacheProfiler* m_L1I_cache_profiler_ptr; - CacheProfiler* m_L2_cache_profiler_ptr; - AddressProfiler* m_address_profiler_ptr; - AddressProfiler* m_inst_profiler_ptr; - - Vector m_instructions_executed_at_start; - Vector m_cycles_executed_at_start; - - ostream* m_periodic_output_file_ptr; - integer_t m_stats_period; - - Time m_ruby_start; - time_t m_real_time_start_time; - - int m_num_BA_unicasts; - int m_num_BA_broadcasts; - - Vector m_perProcTotalMisses; - Vector m_perProcUserMisses; - Vector m_perProcSupervisorMisses; - Vector m_perProcStartTransaction; - Vector m_perProcEndTransaction; - Vector < Vector < integer_t > > m_busyControllerCount; - integer_t m_busyBankCount; - Histogram m_multicast_retry_histogram; - - Histogram m_L1tbeProfile; - Histogram m_L2tbeProfile; - Histogram m_stopTableProfile; - - Histogram m_filter_action_histogram; - Histogram m_tbeProfile; - - Histogram m_sequencer_requests; - Histogram m_store_buffer_size; - Histogram m_store_buffer_blocks; - Histogram m_read_sharing_histogram; - Histogram m_write_sharing_histogram; - Histogram m_all_sharing_histogram; - int64 m_cache_to_cache; - int64 m_memory_to_cache; - - Histogram m_prefetchWaitHistogram; - - Vector m_missLatencyHistograms; - Vector m_machLatencyHistograms; - Histogram m_L2MissLatencyHistogram; - Histogram m_allMissLatencyHistogram; - - Histogram m_allSWPrefetchLatencyHistogram; - Histogram m_SWPrefetchL2MissLatencyHistogram; - Vector m_SWPrefetchLatencyHistograms; - Vector m_SWPrefetchMachLatencyHistograms; - - Histogram m_delayedCyclesHistogram; - Histogram m_delayedCyclesNonPFHistogram; - Vector m_delayedCyclesVCHistograms; - - int m_predictions; - int m_predictionOpportunities; - int m_goodPredictions; - - Histogram m_gets_mask_prediction; - Histogram m_getx_mask_prediction; - Histogram m_explicit_training_mask; - - // For profiling possibly conflicting requests - Map* m_conflicting_map_ptr; - Histogram m_conflicting_histogram; - - Histogram m_outstanding_requests; - Histogram m_outstanding_persistent_requests; - - Histogram m_average_latency_estimate; - - Map* m_watch_address_list_ptr; - // counts all initiated cache request including PUTs - int m_requests; - Map * m_requestProfileMap_ptr; - - // added for MemoryControl: - long long int m_memReq; - long long int m_memBankBusy; - long long int m_memBusBusy; - long long int m_memTfawBusy; - long long int m_memReadWriteBusy; - long long int m_memDataBusBusy; - long long int m_memRefresh; - long long int m_memRead; - long long int m_memWrite; - long long int m_memWaitCycles; - long long int m_memInputQ; - long long int m_memBankQ; - long long int m_memArbWait; - long long int m_memRandBusy; - long long int m_memNotOld; - Vector m_memBankCount; + //added by SS + vector m_memory_control_names; + // Private Methods + void addL2StatSample(GenericRequestType requestType, AccessModeType type, int msgSize, PrefetchBit pfBit, NodeID id); + void addL1DStatSample(const CacheMsg& msg, NodeID id); + void addL1IStatSample(const CacheMsg& msg, NodeID id); + + GenericRequestType CacheRequestType_to_GenericRequestType(const CacheRequestType& type); + + // Private copy constructor and assignment operator + Profiler(const Profiler& obj); + Profiler& operator=(const Profiler& obj); + + // Data Members (m_ prefix) + CacheProfiler* m_L1D_cache_profiler_ptr; + CacheProfiler* m_L1I_cache_profiler_ptr; + CacheProfiler* m_L2_cache_profiler_ptr; + AddressProfiler* m_address_profiler_ptr; + AddressProfiler* m_inst_profiler_ptr; + + Vector m_instructions_executed_at_start; + Vector m_cycles_executed_at_start; + + ostream* m_periodic_output_file_ptr; + integer_t m_stats_period; + + Time m_ruby_start; + time_t m_real_time_start_time; + + int m_num_BA_unicasts; + int m_num_BA_broadcasts; + + Vector m_perProcTotalMisses; + Vector m_perProcUserMisses; + Vector m_perProcSupervisorMisses; + Vector m_perProcStartTransaction; + Vector m_perProcEndTransaction; + Vector < Vector < integer_t > > m_busyControllerCount; + integer_t m_busyBankCount; + Histogram m_multicast_retry_histogram; + + Histogram m_L1tbeProfile; + Histogram m_L2tbeProfile; + Histogram m_stopTableProfile; + + Histogram m_filter_action_histogram; + Histogram m_tbeProfile; + + Histogram m_sequencer_requests; + Histogram m_store_buffer_size; + Histogram m_store_buffer_blocks; + Histogram m_read_sharing_histogram; + Histogram m_write_sharing_histogram; + Histogram m_all_sharing_histogram; + int64 m_cache_to_cache; + int64 m_memory_to_cache; + + Histogram m_prefetchWaitHistogram; + + Vector m_missLatencyHistograms; + Vector m_machLatencyHistograms; + Histogram m_L2MissLatencyHistogram; + Histogram m_allMissLatencyHistogram; + + Histogram m_allSWPrefetchLatencyHistogram; + Histogram m_SWPrefetchL2MissLatencyHistogram; + Vector m_SWPrefetchLatencyHistograms; + Vector m_SWPrefetchMachLatencyHistograms; + + Histogram m_delayedCyclesHistogram; + Histogram m_delayedCyclesNonPFHistogram; + Vector m_delayedCyclesVCHistograms; + + int m_predictions; + int m_predictionOpportunities; + int m_goodPredictions; + + Histogram m_gets_mask_prediction; + Histogram m_getx_mask_prediction; + Histogram m_explicit_training_mask; + + // For profiling possibly conflicting requests + Map* m_conflicting_map_ptr; + Histogram m_conflicting_histogram; + + Histogram m_outstanding_requests; + Histogram m_outstanding_persistent_requests; + + Histogram m_average_latency_estimate; + + Map* m_watch_address_list_ptr; + // counts all initiated cache request including PUTs + int m_requests; + Map * m_requestProfileMap_ptr; + + // added for MemoryControl: + //added by SS + map< string, memory_control_profiler* > m_memory_control_profilers; + + //added by SS + bool m_hot_lines; + bool m_all_instructions; + string m_name; }; @@ -312,9 +320,9 @@ ostream& operator<<(ostream& out, const Profiler& obj); extern inline ostream& operator<<(ostream& out, const Profiler& obj) { - obj.print(out); - out << flush; - return out; + obj.print(out); + out << flush; + return out; } #endif //PROFILER_H diff --git a/src/mem/ruby/recorder/CacheRecorder.cc b/src/mem/ruby/recorder/CacheRecorder.cc index 21193ba68..672c175e3 100644 --- a/src/mem/ruby/recorder/CacheRecorder.cc +++ b/src/mem/ruby/recorder/CacheRecorder.cc @@ -36,44 +36,40 @@ #include "mem/ruby/recorder/TraceRecord.hh" #include "mem/ruby/eventqueue/RubyEventQueue.hh" #include "mem/gems_common/PrioHeap.hh" +#include "gzstream.hh" CacheRecorder::CacheRecorder() { - std::cout << __FILE__ << "(" << __LINE__ << "): Not implemented" << std::endl; - // m_records_ptr = new PrioHeap; + m_records_ptr = new PrioHeap; } CacheRecorder::~CacheRecorder() { - std::cout << __FILE__ << "(" << __LINE__ << "): Not implemented" << std::endl; - // delete m_records_ptr; + delete m_records_ptr; } -void CacheRecorder::addRecord(NodeID id, const Address& data_addr, const Address& pc_addr, CacheRequestType type, Time time) +void CacheRecorder::addRecord(const string & sequencer_name, const Address& data_addr, const Address& pc_addr, RubyRequestType type, Time time) { - std::cout << __FILE__ << "(" << __LINE__ << "): Not implemented" << std::endl; - // m_records_ptr->insert(TraceRecord(id, data_addr, pc_addr, type, time)); + m_records_ptr->insert(TraceRecord(sequencer_name, data_addr, pc_addr, type, time)); } int CacheRecorder::dumpRecords(string filename) { - std::cout << __FILE__ << "(" << __LINE__ << "): Not implemented" << std::endl; - // ogzstream out(filename.c_str()); - // if (out.fail()) { - // cout << "Error: error opening file '" << filename << "'" << endl; - // return 0; - // } + ogzstream out(filename.c_str()); + if (out.fail()) { + cout << "Error: error opening file '" << filename << "'" << endl; + return 0; + } - // int counter = 0; - // while (m_records_ptr->size() != 0) { - // TraceRecord record = m_records_ptr->extractMin(); - // record.output(out); - // counter++; - // } - // return counter; + int counter = 0; + while (m_records_ptr->size() != 0) { + TraceRecord record = m_records_ptr->extractMin(); + record.output(out); + counter++; + } + return counter; } void CacheRecorder::print(ostream& out) const { - std::cout << __FILE__ << "(" << __LINE__ << "): Not implemented" << std::endl; } diff --git a/src/mem/ruby/recorder/CacheRecorder.hh b/src/mem/ruby/recorder/CacheRecorder.hh index 0f69f8478..144e841b3 100644 --- a/src/mem/ruby/recorder/CacheRecorder.hh +++ b/src/mem/ruby/recorder/CacheRecorder.hh @@ -38,6 +38,8 @@ #ifndef CACHERECORDER_H #define CACHERECORDER_H +#include "mem/ruby/libruby_internal.hh" + #include "mem/ruby/common/Global.hh" #include "mem/ruby/system/NodeID.hh" #include "mem/protocol/CacheRequestType.hh" @@ -55,7 +57,7 @@ public: ~CacheRecorder(); // Public Methods - void addRecord(NodeID id, const Address& data_addr, const Address& pc_addr, CacheRequestType type, Time time); + void addRecord(const string & sequencer_name, const Address& data_addr, const Address& pc_addr, RubyRequestType type, Time time); int dumpRecords(string filename); void print(ostream& out) const; diff --git a/src/mem/ruby/recorder/TraceRecord.cc b/src/mem/ruby/recorder/TraceRecord.cc index 31b83690e..1521d2a3f 100644 --- a/src/mem/ruby/recorder/TraceRecord.cc +++ b/src/mem/ruby/recorder/TraceRecord.cc @@ -35,13 +35,11 @@ #include "mem/ruby/recorder/TraceRecord.hh" #include "mem/ruby/system/Sequencer.hh" #include "mem/ruby/system/System.hh" -#include "mem/ruby/slicc_interface/AbstractChip.hh" #include "mem/protocol/CacheMsg.hh" -#include "mem/packet.hh" -TraceRecord::TraceRecord(NodeID id, const Address& data_addr, const Address& pc_addr, CacheRequestType type, Time time) +TraceRecord::TraceRecord(const string & sequencer_name, const Address& data_addr, const Address& pc_addr, RubyRequestType type, Time time) { - m_node_num = id; + m_sequencer_name = sequencer_name; m_data_address = data_addr; m_pc_address = pc_addr; m_time = time; @@ -49,8 +47,8 @@ TraceRecord::TraceRecord(NodeID id, const Address& data_addr, const Address& pc_ // Don't differentiate between store misses and atomic requests in // the trace - if (m_type == CacheRequestType_ATOMIC) { - m_type = CacheRequestType_ST; + if (m_type == RubyRequestType_RMW) { + m_type = RubyRequestType_ST; } } @@ -62,7 +60,7 @@ TraceRecord::TraceRecord(const TraceRecord& obj) TraceRecord& TraceRecord::operator=(const TraceRecord& obj) { - m_node_num = obj.m_node_num; + m_sequencer_name = obj.m_sequencer_name; m_time = obj.m_time; m_data_address = obj.m_data_address; m_pc_address = obj.m_pc_address; @@ -74,32 +72,17 @@ void TraceRecord::issueRequest() const { // Lookup sequencer pointer from system // Note that the chip index also needs to take into account SMT configurations - AbstractChip* chip_ptr = g_system_ptr->getChip(m_node_num/RubyConfig::numberOfProcsPerChip()/RubyConfig::numberofSMTThreads()); - assert(chip_ptr != NULL); - Sequencer* sequencer_ptr = chip_ptr->getSequencer((m_node_num/RubyConfig::numberofSMTThreads())%RubyConfig::numberOfProcsPerChip()); + Sequencer* sequencer_ptr = RubySystem::getSequencer(m_sequencer_name); assert(sequencer_ptr != NULL); - Addr data_addr = m_data_address.getAddress(); - Addr pc_addr = m_pc_address.getAddress(); - Request request(0, data_addr, 0, Flags(Request::PREFETCH), pc_addr, m_node_num, 0); - MemCmd::Command command; - if (m_type == CacheRequestType_LD || m_type == CacheRequestType_IFETCH) - command = MemCmd::ReadReq; - else if (m_type == CacheRequestType_ST) - command = MemCmd::WriteReq; - else if (m_type == CacheRequestType_ATOMIC) - command = MemCmd::SwapReq; // TODO -- differentiate between atomic types - else - assert(false); - - Packet pkt(&request, command, 0); // TODO -- make dest a real NodeID + RubyRequest request(m_data_address.getAddress(), NULL, RubySystem::getBlockSizeBytes(), m_pc_address.getAddress(), m_type, RubyAccessMode_User); // Clear out the sequencer while (!sequencer_ptr->empty()) { g_eventQueue_ptr->triggerEvents(g_eventQueue_ptr->getTime() + 100); } - sequencer_ptr->makeRequest(&pkt); + sequencer_ptr->makeRequest(request); // Clear out the sequencer while (!sequencer_ptr->empty()) { @@ -109,12 +92,12 @@ void TraceRecord::issueRequest() const void TraceRecord::print(ostream& out) const { - out << "[TraceRecord: Node, " << m_node_num << ", " << m_data_address << ", " << m_pc_address << ", " << m_type << ", Time: " << m_time << "]"; + out << "[TraceRecord: Node, " << m_sequencer_name << ", " << m_data_address << ", " << m_pc_address << ", " << m_type << ", Time: " << m_time << "]"; } void TraceRecord::output(ostream& out) const { - out << m_node_num << " "; + out << m_sequencer_name << " "; m_data_address.output(out); out << " "; m_pc_address.output(out); @@ -125,13 +108,13 @@ void TraceRecord::output(ostream& out) const bool TraceRecord::input(istream& in) { - in >> m_node_num; + in >> m_sequencer_name; m_data_address.input(in); m_pc_address.input(in); string type; if (!in.eof()) { in >> type; - m_type = string_to_CacheRequestType(type); + m_type = string_to_RubyRequestType(type); // Ignore the rest of the line char c = '\0'; diff --git a/src/mem/ruby/recorder/TraceRecord.hh b/src/mem/ruby/recorder/TraceRecord.hh index cfe2ff9e3..081d392e5 100644 --- a/src/mem/ruby/recorder/TraceRecord.hh +++ b/src/mem/ruby/recorder/TraceRecord.hh @@ -39,17 +39,18 @@ #ifndef TRACERECORD_H #define TRACERECORD_H +#include "mem/ruby/libruby_internal.hh" + #include "mem/ruby/common/Global.hh" #include "mem/ruby/common/Address.hh" #include "mem/ruby/system/NodeID.hh" -#include "mem/protocol/CacheRequestType.hh" class CacheMsg; class TraceRecord { public: // Constructors - TraceRecord(NodeID id, const Address& data_addr, const Address& pc_addr, CacheRequestType type, Time time); - TraceRecord() { m_node_num = 0; m_time = 0; m_type = CacheRequestType_NULL; } + TraceRecord(const string & sequencer_name, const Address& data_addr, const Address& pc_addr, RubyRequestType type, Time time); + TraceRecord() { m_sequencer_name = ""; m_time = 0; m_type = RubyRequestType_NULL; } // Destructor // ~TraceRecord(); @@ -69,11 +70,11 @@ private: // Private Methods // Data Members (m_ prefix) - NodeID m_node_num; + string m_sequencer_name; Time m_time; Address m_data_address; Address m_pc_address; - CacheRequestType m_type; + RubyRequestType m_type; }; inline extern bool node_less_then_eq(const TraceRecord& n1, const TraceRecord& n2); diff --git a/src/mem/ruby/recorder/Tracer.cc b/src/mem/ruby/recorder/Tracer.cc index 896bfd31e..d2df544d8 100644 --- a/src/mem/ruby/recorder/Tracer.cc +++ b/src/mem/ruby/recorder/Tracer.cc @@ -37,16 +37,41 @@ #include "mem/ruby/eventqueue/RubyEventQueue.hh" #include "mem/gems_common/PrioHeap.hh" #include "mem/ruby/system/System.hh" +#include "mem/ruby/config/RubyConfig.hh" -Tracer::Tracer() +//added by SS +Tracer::Tracer(const string & name) { + m_name = name; m_enabled = false; } +//commented by SS +//Tracer::Tracer() +//{ +// m_enabled = false; +//} + Tracer::~Tracer() { } +void Tracer::init(const vector & argv) +{ + m_warmup_length = 0; + + for (size_t i=0; i 0); +} + void Tracer::startTrace(string filename) { if (m_enabled) { @@ -73,10 +98,10 @@ void Tracer::stopTrace() m_enabled = false; } -void Tracer::traceRequest(NodeID id, const Address& data_addr, const Address& pc_addr, CacheRequestType type, Time time) +void Tracer::traceRequest(const string & sequencer_name, const Address& data_addr, const Address& pc_addr, RubyRequestType type, Time time) { assert(m_enabled == true); - TraceRecord tr(id, data_addr, pc_addr, type, time); + TraceRecord tr(sequencer_name, data_addr, pc_addr, type, time); tr.output(m_trace_file); } @@ -104,10 +129,16 @@ int Tracer::playbackTrace(string filename) ok = record.input(in); // Clear the statistics after warmup - if (counter == g_trace_warmup_length) { - cout << "Clearing stats after warmup of length " << g_trace_warmup_length << endl; +/* if (counter == RubyConfig::getTraceWarmupLength()) { + cout << "Clearing stats after warmup of length " << RubyConfig::getTraceWarmupLength() << endl; g_system_ptr->clearStats(); } +*/ + if (counter == m_warmup_length) { + cout << "Clearing stats after warmup of length " << m_warmup_length << endl; + g_system_ptr->clearStats(); + } + } // Flush the prefetches through the system diff --git a/src/mem/ruby/recorder/Tracer.hh b/src/mem/ruby/recorder/Tracer.hh index 0f78f54b2..27a1c95e1 100644 --- a/src/mem/ruby/recorder/Tracer.hh +++ b/src/mem/ruby/recorder/Tracer.hh @@ -38,6 +38,8 @@ #ifndef TRACER_H #define TRACER_H +#include "mem/ruby/libruby_internal.hh" + #include "mem/ruby/common/Global.hh" #include "mem/ruby/system/NodeID.hh" #include "mem/protocol/CacheRequestType.hh" @@ -50,7 +52,8 @@ class TraceRecord; class Tracer { public: // Constructors - Tracer(); +// Tracer(); + Tracer(const string & name); // Destructor ~Tracer(); @@ -59,12 +62,13 @@ public: void startTrace(string filename); void stopTrace(); bool traceEnabled() { return m_enabled; } - void traceRequest(NodeID id, const Address& data_addr, const Address& pc_addr, CacheRequestType type, Time time); + void traceRequest(const string & sequencer_name, const Address& data_addr, const Address& pc_addr, RubyRequestType type, Time time); void print(ostream& out) const; // Public Class Methods - static int playbackTrace(string filename); + int playbackTrace(string filename); + void init(const vector & argv); private: // Private Methods @@ -75,6 +79,10 @@ private: // Data Members (m_ prefix) ogzstream m_trace_file; bool m_enabled; + + //added by SS + int m_warmup_length; + string m_name; }; // Output operator declaration diff --git a/src/mem/ruby/slicc_interface/AbstractCacheEntry.cc b/src/mem/ruby/slicc_interface/AbstractCacheEntry.cc index 60ca412ad..83039a9b0 100644 --- a/src/mem/ruby/slicc_interface/AbstractCacheEntry.cc +++ b/src/mem/ruby/slicc_interface/AbstractCacheEntry.cc @@ -37,6 +37,8 @@ #include "mem/ruby/slicc_interface/AbstractCacheEntry.hh" AbstractCacheEntry::AbstractCacheEntry() { + m_Address.setAddress(0); + m_Permission = AccessPermission_NotPresent; } // still need to define destructor for subclasses diff --git a/src/mem/ruby/slicc_interface/AbstractCacheEntry.hh b/src/mem/ruby/slicc_interface/AbstractCacheEntry.hh index 18dc16ca8..be1f14b05 100644 --- a/src/mem/ruby/slicc_interface/AbstractCacheEntry.hh +++ b/src/mem/ruby/slicc_interface/AbstractCacheEntry.hh @@ -41,6 +41,8 @@ #include "mem/ruby/common/Address.hh" #include "mem/protocol/AccessPermission.hh" +class DataBlock; + class AbstractCacheEntry { public: // Constructors @@ -53,6 +55,7 @@ public: // The methods below are those called by ruby runtime, add when it is // absolutely necessary and should all be virtual function. + virtual DataBlock& getDataBlk() = 0; virtual void print(ostream& out) const = 0; diff --git a/src/mem/ruby/slicc_interface/AbstractChip.cc b/src/mem/ruby/slicc_interface/AbstractChip.cc deleted file mode 100644 index 021c95b9d..000000000 --- a/src/mem/ruby/slicc_interface/AbstractChip.cc +++ /dev/null @@ -1,47 +0,0 @@ - -/* - * Copyright (c) 1999-2008 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. - */ - -/* - * $Id$ - * - * Description: See AbstractChip.hh - * - */ - -#include "mem/ruby/slicc_interface/AbstractChip.hh" - -AbstractChip::AbstractChip(NodeID id, Network* net_ptr) { - m_id = id; - m_net_ptr = net_ptr; - m_L1Cache_sequencer_vec.setSize(0); -} - -// still need to be defined for subclasses -AbstractChip::~AbstractChip() { -} diff --git a/src/mem/ruby/slicc_interface/AbstractChip.hh b/src/mem/ruby/slicc_interface/AbstractChip.hh deleted file mode 100644 index d47dd6306..000000000 --- a/src/mem/ruby/slicc_interface/AbstractChip.hh +++ /dev/null @@ -1,126 +0,0 @@ - -/* - * Copyright (c) 1999-2008 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. - */ - -/* - * $Id$ - * - * Description: Common base class for a machine chip. - * - */ - -#ifndef ABSTRACT_CHIP_H -#define ABSTRACT_CHIP_H - -#include "mem/ruby/common/Global.hh" -#include "mem/ruby/system/NodeID.hh" -#include "mem/ruby/config/RubyConfig.hh" -#include "mem/protocol/L1Cache_Entry.hh" -#include "mem/ruby/common/Address.hh" -#include "mem/gems_common/Vector.hh" - -class Network; -class Sequencer; -class StoreBuffer; -class ENTRY; -class MessageBuffer; -class CacheRecorder; -class TransactionInterfaceManager; - -template class CacheMemory; - -class AbstractChip { -public: - // Constructors - AbstractChip(NodeID chip_number, Network* net_ptr); - - // Destructor, prevent from being instantiated - virtual ~AbstractChip() = 0; - - // Public Methods - NodeID getID() const { return m_id; }; - Network* getNetwork() const { return m_net_ptr; }; - Sequencer* getSequencer(int index) const { return m_L1Cache_sequencer_vec[index]; }; - TransactionInterfaceManager* getTransactionInterfaceManager(int index) const { return m_L1Cache_xact_mgr_vec[index]; }; - void setTransactionInterfaceManager(TransactionInterfaceManager* manager, int index) { m_L1Cache_xact_mgr_vec[index] = manager; } - - // used when CHECK_COHERENCE is enabled. See RubySystem::checkGlobalCoherence() - virtual bool isBlockExclusive(const Address& addr) const { return false; } - virtual bool isBlockShared(const Address& addr) const { return false; } - - // cache dump functions - virtual void recordCacheContents(CacheRecorder& tr) const = 0; - virtual void dumpCaches(ostream& out) const = 0; - virtual void dumpCacheData(ostream& out) const = 0; - - virtual void printConfig(ostream& out) = 0; - virtual void print(ostream& out) const = 0; - - // pulic data structures - Vector < CacheMemory* > m_L1Cache_L1DcacheMemory_vec; - Vector < CacheMemory* > m_L1Cache_L1IcacheMemory_vec; - Vector < CacheMemory* > m_L1Cache_cacheMemory_vec; - Vector < CacheMemory* > m_L1Cache_L2cacheMemory_vec; - Vector < CacheMemory* > m_L2Cache_L2cacheMemory_vec; - - // added so that the prefetcher and sequencer can access the L1 and L2 request queues - Vector < MessageBuffer* > m_L1Cache_optionalQueue_vec; - Vector < MessageBuffer* >m_L1Cache_mandatoryQueue_vec; - - // TSO storebuffer - Vector < StoreBuffer* > m_L1Cache_storeBuffer_vec; - - // TM transaction manager - Vector < TransactionInterfaceManager* > m_L1Cache_xact_mgr_vec; - -protected: - - // Data Members (m_ prefix) - NodeID m_id; // Chip id - Network* m_net_ptr; // Points to the Network simulator - Vector < Sequencer* > m_L1Cache_sequencer_vec; // All chip should have a sequencer - - -}; - -// Output operator declaration -ostream& operator<<(ostream& out, const AbstractChip& obj); - -// ******************* Definitions ******************* - -// Output operator definition -extern inline -ostream& operator<<(ostream& out, const AbstractChip& obj) -{ - obj.print(out); - out << flush; - return out; -} - -#endif //ABSTRACT_CHIP_H - diff --git a/src/mem/ruby/slicc_interface/AbstractController.hh b/src/mem/ruby/slicc_interface/AbstractController.hh new file mode 100644 index 000000000..3a93cc745 --- /dev/null +++ b/src/mem/ruby/slicc_interface/AbstractController.hh @@ -0,0 +1,33 @@ + +#ifndef ABSTRACTCONTROLLER_H +#define ABSTRACTCONTROLLER_H + +#include "mem/ruby/common/Consumer.hh" +#include "mem/protocol/MachineType.hh" + +class MessageBuffer; +class Network; + +class AbstractController : public Consumer { +public: + AbstractController() {} + virtual void init(Network* net_ptr, const vector & argv) = 0; + + // returns the number of controllers created of the specific subtype + // virtual int getNumberOfControllers() const = 0; + virtual MessageBuffer* getMandatoryQueue() const = 0; + virtual const int & getVersion() const = 0; + virtual const string toString() const = 0; // returns text version of controller type + virtual const string getName() const = 0; // return instance name + virtual const MachineType getMachineType() const = 0; + + virtual void print(ostream & out) const = 0; + virtual void printStats(ostream & out) const = 0; + virtual void printConfig(ostream & out) const = 0; + virtual void wakeup() = 0; + // virtual void dumpStats(ostream & out) = 0; + virtual void clearStats() = 0; + +}; + +#endif diff --git a/src/mem/ruby/slicc_interface/RubySlicc_ComponentMapping.hh b/src/mem/ruby/slicc_interface/RubySlicc_ComponentMapping.hh index bf5778479..9ece7ae65 100644 --- a/src/mem/ruby/slicc_interface/RubySlicc_ComponentMapping.hh +++ b/src/mem/ruby/slicc_interface/RubySlicc_ComponentMapping.hh @@ -42,6 +42,7 @@ #include "mem/ruby/common/Set.hh" #include "mem/ruby/common/NetDest.hh" #include "mem/protocol/GenericMachineType.hh" +#include "mem/ruby/system/DirectoryMemory.hh" #ifdef MACHINETYPE_L1Cache #define MACHINETYPE_L1CACHE_ENUM MachineType_L1Cache @@ -61,44 +62,22 @@ #define MACHINETYPE_L3CACHE_ENUM MachineType_NUM #endif +/* #ifdef MACHINETYPE_PersistentArbiter #define MACHINETYPE_PERSISTENTARBITER_ENUM MachineType_PersistentArbiter #else #define MACHINETYPE_PERSISTENTARBITER_ENUM MachineType_NUM #endif - -#ifdef MACHINETYPE_Collector -#define MACHINETYPE_COLLECTOR_ENUM MachineType_Collector -#else -#define MACHINETYPE_COLLECTOR_ENUM MachineType_NUM -#endif - - -// used to determine the correct L1 set -// input parameters are the address and number of set bits for the L1 cache -// returns a value between 0 and the total number of L1 cache sets -inline -int map_address_to_L1CacheSet(const Address& addr, int cache_num_set_bits) -{ - return addr.bitSelect(RubyConfig::dataBlockBits(), - RubyConfig::dataBlockBits()+cache_num_set_bits-1); -} - -// used to determine the correct L2 set -// input parameters are the address and number of set bits for the L2 cache -// returns a value between 0 and the total number of L2 cache sets -inline -int map_address_to_L2CacheSet(const Address& addr, int cache_num_set_bits) +*/ +/* +inline MachineID map_Address_to_L2Cache(const Address & addr) { - assert(cache_num_set_bits == L2_CACHE_NUM_SETS_BITS); // ensure the l2 bank mapping functions agree with l2 set bits - - if (MAP_L2BANKS_TO_LOWEST_BITS) { - return addr.bitSelect(RubyConfig::dataBlockBits()+RubyConfig::L2CachePerChipBits(), - RubyConfig::dataBlockBits()+RubyConfig::L2CachePerChipBits()+cache_num_set_bits-1); - } else { - return addr.bitSelect(RubyConfig::dataBlockBits(), - RubyConfig::dataBlockBits()+cache_num_set_bits-1); - } + int L2bank = 0; + MachineID mach = {MACHINETYPE_L2CACHE_ENUM, 0}; + L2bank = addr.bitSelect(RubySystem::getBlockSizeBits(), + RubySystem::getBlockSizeBits() + RubyConfig::getNumberOfCachesPerLevel(2)-1); + mach.num = L2bank; + return mach; } // input parameter is the base ruby node of the L1 cache @@ -106,16 +85,18 @@ int map_address_to_L2CacheSet(const Address& addr, int cache_num_set_bits) inline MachineID map_L1CacheMachId_to_L2Cache(const Address& addr, MachineID L1CacheMachId) { + return map_Address_to_L2Cache(addr); + int L2bank = 0; MachineID mach = {MACHINETYPE_L2CACHE_ENUM, 0}; if (RubyConfig::L2CachePerChipBits() > 0) { - if (MAP_L2BANKS_TO_LOWEST_BITS) { - L2bank = addr.bitSelect(RubyConfig::dataBlockBits(), - RubyConfig::dataBlockBits()+RubyConfig::L2CachePerChipBits()-1); + if (RubyConfig::getMAP_L2BANKS_TO_LOWEST_BITS()) { + L2bank = addr.bitSelect(RubySystem::getBlockSizeBits(), + RubySystem::getBlockSizeBits()+RubyConfig::L2CachePerChipBits()-1); } else { - L2bank = addr.bitSelect(RubyConfig::dataBlockBits()+L2_CACHE_NUM_SETS_BITS, - RubyConfig::dataBlockBits()+L2_CACHE_NUM_SETS_BITS+RubyConfig::L2CachePerChipBits()-1); + L2bank = addr.bitSelect(RubySystem::getBlockSizeBits()+RubyConfig::getL2_CACHE_NUM_SETS_BITS(), + RubySystem::getBlockSizeBits()+RubyConfig::getL2_CACHE_NUM_SETS_BITS()+RubyConfig::L2CachePerChipBits()-1); } } @@ -126,72 +107,38 @@ MachineID map_L1CacheMachId_to_L2Cache(const Address& addr, MachineID L1CacheMac + L2bank; // bank # assert(mach.num < RubyConfig::numberOfL2Cache()); return mach; + } + // used to determine the correct L2 bank // input parameter is the base ruby node of the L2 cache // returns a value between 0 and total_L2_Caches_within_the_system + inline MachineID map_L2ChipId_to_L2Cache(const Address& addr, NodeID L2ChipId) { + return map_Address_to_L2Cache(addr); + assert(L2ChipId < RubyConfig::numberOfChips()); int L2bank = 0; MachineID mach = {MACHINETYPE_L2CACHE_ENUM, 0}; + L2bank = addr.bitSelect(RubySystem::getBlockSizeBits(), + RubySystem::getBlockSizeBits() + RubyConfig::numberOfCachesPerLevel(2)-1); + mach.num = L2bank; + return mach - if (RubyConfig::L2CachePerChipBits() > 0) { - if (MAP_L2BANKS_TO_LOWEST_BITS) { - L2bank = addr.bitSelect(RubyConfig::dataBlockBits(), - RubyConfig::dataBlockBits()+RubyConfig::L2CachePerChipBits()-1); - } else { - L2bank = addr.bitSelect(RubyConfig::dataBlockBits()+L2_CACHE_NUM_SETS_BITS, - RubyConfig::dataBlockBits()+L2_CACHE_NUM_SETS_BITS+RubyConfig::L2CachePerChipBits()-1); - } - } - - assert(L2bank < RubyConfig::numberOfL2CachePerChip()); - assert(L2bank >= 0); - - mach.num = L2ChipId*RubyConfig::numberOfL2CachePerChip() // base # - + L2bank; // bank # - assert(mach.num < RubyConfig::numberOfL2Cache()); - return mach; } + */ + // used to determine the home directory // returns a value between 0 and total_directories_within_the_system inline NodeID map_Address_to_DirectoryNode(const Address& addr) { - NodeID dirNode = 0; - - if (RubyConfig::memoryBits() > 0) { - dirNode = addr.bitSelect(RubyConfig::dataBlockBits(), - RubyConfig::dataBlockBits()+RubyConfig::memoryBits()-1); - } - - // Index indexHighPortion = address.bitSelect(MEMORY_SIZE_BITS-1, PAGE_SIZE_BITS+NUMBER_OF_MEMORY_MODULE_BITS); - // Index indexLowPortion = address.bitSelect(DATA_BLOCK_BITS, PAGE_SIZE_BITS-1); - - //Index index = indexLowPortion | (indexHighPortion << (PAGE_SIZE_BITS - DATA_BLOCK_BITS)); - -/* - -ADDRESS_WIDTH MEMORY_SIZE_BITS PAGE_SIZE_BITS DATA_BLOCK_BITS - | | | | - \ / \ / \ / \ / 0 - ----------------------------------------------------------------------- - | unused |xxxxxxxxxxxxxxx| |xxxxxxxxxxxxxxx| | - | |xxxxxxxxxxxxxxx| |xxxxxxxxxxxxxxx| | - ----------------------------------------------------------------------- - indexHighPortion indexLowPortion - <-------> - NUMBER_OF_MEMORY_MODULE_BITS - */ - - assert(dirNode < RubyConfig::numberOfMemories()); - assert(dirNode >= 0); - return dirNode; + return DirectoryMemory::mapAddressToDirectoryVersion(addr); } // used to determine the home directory @@ -204,29 +151,13 @@ MachineID map_Address_to_Directory(const Address &addr) } inline -MachineID map_Address_to_CentralArbiterNode(const Address& addr) -{ - MachineType t = MACHINETYPE_PERSISTENTARBITER_ENUM; - MachineID mach = {t, map_Address_to_DirectoryNode(addr)}; - - assert(mach.num < RubyConfig::numberOfMemories()); - assert(mach.num >= 0); - return mach; -} - -inline -NetDest getMultiStaticL2BankNetDest(const Address& addr, const Set& sharers) // set of L2RubyNodes +MachineID map_Address_to_DMA(const Address & addr) { - NetDest dest; - - for (int i = 0; i < sharers.getSize(); i++) { - if (sharers.isElement(i)) { - dest.add(map_L2ChipId_to_L2Cache(addr,i)); - } - } - return dest; + MachineID dma = {MachineType_DMA, 0}; + return dma; } +/* inline NetDest getOtherLocalL1IDs(MachineID L1) { @@ -244,119 +175,7 @@ NetDest getOtherLocalL1IDs(MachineID L1) return ret; } - -inline -NetDest getLocalL1IDs(MachineID mach) -{ - assert(MACHINETYPE_L1CACHE_ENUM != MachineType_NUM); - - NetDest ret; - - if (mach.type == MACHINETYPE_L1CACHE_ENUM) { - - int start = (mach.num / RubyConfig::numberOfL1CachePerChip()) * RubyConfig::numberOfProcsPerChip(); - - for (int i = start; i < (start + RubyConfig::numberOfProcsPerChip()); i++) { - MachineID mach = { MACHINETYPE_L1CACHE_ENUM, i }; - ret.add( mach ); - } - } - else if (mach.type == MACHINETYPE_L2CACHE_ENUM) { - - int chip = mach.num/RubyConfig::numberOfL2CachePerChip(); - int start = ( chip*RubyConfig::numberOfL1CachePerChip()); - for (int i = start; i < (start + RubyConfig::numberOfL1CachePerChip()); i++) { - MachineID mach = { MACHINETYPE_L1CACHE_ENUM, i }; - ret.add( mach ); - } - } - - return ret; -} - -inline -NetDest getExternalL1IDs(MachineID L1) -{ - NetDest ret; - - assert(MACHINETYPE_L1CACHE_ENUM != MachineType_NUM); - - for (int i = 0; i < RubyConfig::numberOfProcessors(); i++) { - // ret.add( (NodeID) i); - MachineID mach = { MACHINETYPE_L1CACHE_ENUM, i }; - ret.add( mach ); - } - - ret.removeNetDest(getLocalL1IDs(L1)); - - return ret; -} - -inline -bool isLocalProcessor(MachineID thisId, MachineID tarID) -{ - int start = (thisId.num / RubyConfig::numberOfProcsPerChip()) * RubyConfig::numberOfProcsPerChip(); - - for (int i = start; i < (start + RubyConfig::numberOfProcsPerChip()); i++) { - if (i == tarID.num) { - return true; - } - } - return false; -} - - -inline -NetDest getAllPertinentL2Banks(const Address& addr) // set of L2RubyNodes -{ - NetDest dest; - - for (int i = 0; i < RubyConfig::numberOfChips(); i++) { - dest.add(map_L2ChipId_to_L2Cache(addr,i)); - } - return dest; -} - -inline -bool isL1OnChip(MachineID L1machID, NodeID L2NodeID) -{ - if (L1machID.type == MACHINETYPE_L1CACHE_ENUM) { - return (L1machID.num == L2NodeID); - } else { - return false; - } -} - -inline -bool isL2OnChip(MachineID L2machID, NodeID L2NodeID) -{ - if (L2machID.type == MACHINETYPE_L2CACHE_ENUM) { - return (L2machID.num == L2NodeID); - } else { - return false; - } -} - -inline -NodeID closest_clockwise_distance(NodeID this_node, NodeID next_node) -{ - if (this_node <= next_node) { - return (next_node - this_node); - } else { - return (next_node - this_node + RubyConfig::numberOfChips()); - } -} - -inline -bool closer_clockwise_processor(NodeID this_node, NodeID newer, NodeID older) -{ - return (closest_clockwise_distance(this_node, newer) < closest_clockwise_distance(this_node, older)); -} - -extern inline NodeID getChipID(MachineID L2machID) -{ - return (L2machID.num%RubyConfig::numberOfChips())/RubyConfig::numberOfProcsPerChip(); -} +*/ extern inline NodeID machineIDToNodeID(MachineID machID) { @@ -364,11 +183,6 @@ extern inline NodeID machineIDToNodeID(MachineID machID) return machID.num; } -extern inline NodeID machineIDToVersion(MachineID machID) -{ - return machID.num/RubyConfig::numberOfChips(); -} - extern inline MachineType machineIDToMachineType(MachineID machID) { return machID.type; @@ -379,25 +193,22 @@ extern inline NodeID L1CacheMachIDToProcessorNum(MachineID machID) assert(machID.type == MachineType_L1Cache); return machID.num; } - +/* extern inline NodeID L2CacheMachIDToChipID(MachineID machID) { assert(machID.type == MACHINETYPE_L2CACHE_ENUM); - return machID.num/RubyConfig::numberOfL2CachePerChip(); -} - -extern inline MachineID getCollectorDest(MachineID L1MachID) -{ - MachineID mach = {MACHINETYPE_COLLECTOR_ENUM, L1MachID.num}; - return mach; -} - -extern inline MachineID getCollectorL1Cache(MachineID colID) -{ - MachineID mach = {MACHINETYPE_L1CACHE_ENUM, colID.num}; - return mach; + int L2bank = machID.num; + int banks_seen = 0; + for (int i=0;igetProfiler()->addAddressTraceSample(msg, id); - g_system_ptr->getProfiler()->profileConflictingRequests(msg.getAddress()); + g_system_ptr->getProfiler()->profileConflictingRequests(msg.getLineAddress()); g_system_ptr->getProfiler()->addSecondaryStatSample(msg.getType(), msg.getAccessMode(), msg.getSize(), msg.getPrefetch(), id); @@ -93,9 +93,6 @@ void profile_miss(const CacheMsg& msg, NodeID id) void profile_L1Cache_miss(const CacheMsg& msg, NodeID id) { - // only called by protocols assuming non-zero cycle hits - ASSERT (REMOVE_SINGLE_CYCLE_DCACHE_FAST_PATH); - g_system_ptr->getProfiler()->addPrimaryStatSample(msg, id); } @@ -139,25 +136,5 @@ void profileGetS(const Address& datablock, const Address& PC, const Set& owner, g_system_ptr->getProfiler()->getAddressProfiler()->profileGetS(datablock, PC, owner, sharers, requestor); } -void profileOverflow(const Address & addr, MachineID mach) -{ -#if 0 - if(mach.type == MACHINETYPE_L1CACHE_ENUM){ - // for L1 overflows - int proc_num = L1CacheMachIDToProcessorNum(mach); - int chip_num = proc_num/RubyConfig::numberOfProcsPerChip(); - assert(0); - // g_system_ptr->getChip(chip_num)->m_L1Cache_xact_mgr_vec[proc_num]->profileOverflow(addr, true); - } - else if(mach.type == MACHINETYPE_L2CACHE_ENUM){ - // for L2 overflows - int chip_num = L2CacheMachIDToChipID(mach); - for(int p=0; p < RubyConfig::numberOfProcessors(); ++p){ - assert(0); - // g_system_ptr->getChip(chip_num)->m_L1Cache_xact_mgr_vec[p]->profileOverflow(addr, false); - } - } -#endif -} diff --git a/src/mem/ruby/slicc_interface/RubySlicc_Util.hh b/src/mem/ruby/slicc_interface/RubySlicc_Util.hh index d0fc0c4a5..d8692951e 100644 --- a/src/mem/ruby/slicc_interface/RubySlicc_Util.hh +++ b/src/mem/ruby/slicc_interface/RubySlicc_Util.hh @@ -54,6 +54,7 @@ #include "mem/protocol/MessageSizeType.hh" #include "mem/ruby/network/Network.hh" #include "mem/protocol/PrefetchBit.hh" +#include "mem/ruby/system/System.hh" #include "mem/ruby/slicc_interface/RubySlicc_ComponentMapping.hh" @@ -67,7 +68,7 @@ extern inline int random(int n) extern inline bool multicast_retry() { - if (RANDOMIZATION) { + if (RubySystem::getRandomization()) { return (random() & 0x1); } else { return true; @@ -111,15 +112,18 @@ extern inline int MessageSizeTypeToInt(MessageSizeType size_type) return MessageSizeType_to_int(size_type); } +/* extern inline int numberOfNodes() { return RubyConfig::numberOfChips(); } - +*/ +/* extern inline int numberOfL1CachePerChip() { - return RubyConfig::numberOfL1CachePerChip(); + return RubyConfig::getNumberOfCachesPerLevelPerChip(1,0); } +*/ extern inline bool long_enough_ago(Time event) { @@ -149,7 +153,7 @@ extern inline Time getTimeMinusTime(Time t1, Time t2) extern inline Time getPreviousDelayedCycles(Time t1, Time t2) { - if (RANDOMIZATION) { // when randomizing delayed + if (RubySystem::getRandomization()) { // when randomizing delayed return 0; } else { return getTimeMinusTime(t1, t2); @@ -167,39 +171,40 @@ extern inline Time time_to_int(Time time) return time; } - +/* extern inline bool getFilteringEnabled() { - return g_FILTERING_ENABLED; + return RubyConfig::getFilteringEnabled(); } + extern inline int getRetryThreshold() { - return g_RETRY_THRESHOLD; + return RubyConfig::getRetryThreshold(); } extern inline int getFixedTimeoutLatency() { - return g_FIXED_TIMEOUT_LATENCY; + return RubyConfig::getFixedTimeoutLatency(); } extern inline int N_tokens() { // return N+1 to handle clean writeback - return g_PROCS_PER_CHIP + 1; + return RubyConfig::getProcsPerChip() + 1; // return 1; } extern inline bool distributedPersistentEnabled() { - return g_DISTRIBUTED_PERSISTENT_ENABLED; + return RubyConfig::getDistributedPersistentEnabled(); } extern inline bool getDynamicTimeoutEnabled() { - return g_DYNAMIC_TIMEOUT_ENABLED; + return RubyConfig::getDynamicTimeoutEnabled(); } - +*/ // Appends an offset to an address extern inline Address setOffset(Address addr, int offset) { diff --git a/src/mem/ruby/storebuffer/hfa.hh b/src/mem/ruby/storebuffer/hfa.hh new file mode 100644 index 000000000..abcd96495 --- /dev/null +++ b/src/mem/ruby/storebuffer/hfa.hh @@ -0,0 +1,103 @@ +/* + * Copyright (c) 1999-2008 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. + */ + +// this code was modified to fit into Rochs + +#ifndef _HFA_H_ +#define _HFA_H_ + +using namespace std; + +/* + * Global include file for entire project. + * Should be included first in all ".cc" project files + */ + +/*------------------------------------------------------------------------*/ +/* Includes */ +/*------------------------------------------------------------------------*/ +#include "mem/ruby/common/Global.hh" +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include // va_start(), va_end() +#include // declaration of bzero() + +#include // gettimeofday() includes +#include +#include + +/*------------------------------------------------------------------------*/ +/* Type Includes */ +/*------------------------------------------------------------------------*/ + +#include "mem/ruby/storebuffer/hfatypes.hh" + +/*------------------------------------------------------------------------*/ +/* Forward class declaration(s) */ +/*------------------------------------------------------------------------*/ + +class wait_list_t; +class waiter_t; +class free_list_t; +class pipestate_t; +class pipepool_t; + + +/** Maximum size of a load or store that may occur to/from the memory system. + * (in 64-bit quantities). Currently this is set to 8 * 64-bits = 64-bytes. + */ +const uint32 MEMOP_MAX_SIZE = 8; + +/** 64-bit int memory masks */ +#define MEM_BYTE_MASK 0x00000000000000ffULL +#define MEM_HALF_MASK 0x000000000000ffffULL +#define MEM_WORD_MASK 0x00000000ffffffffULL +#define MEM_EXTD_MASK 0xffffffffffffffffULL +#define MEM_QUAD_MASK 0xffffffffffffffffULL + +#define ISEQ_MASK 0x0000ffffffffffffULL + +/*------------------------------------------------------------------------*/ +/* Configuration Parameters */ +/*------------------------------------------------------------------------*/ + +#define SIM_HALT assert(0); + +#include + +#endif /* _HFA_H_ */ + + diff --git a/src/mem/ruby/storebuffer/hfatypes.hh b/src/mem/ruby/storebuffer/hfatypes.hh new file mode 100644 index 000000000..c4d0de2e6 --- /dev/null +++ b/src/mem/ruby/storebuffer/hfatypes.hh @@ -0,0 +1,80 @@ +/* + * Copyright (c) 1999-2008 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 _HFATYPES_H_ +#define _HFATYPES_H_ + +/* + * Global include file for entire project. + * Should be included first in all ".cc" project files + */ + +/*------------------------------------------------------------------------*/ +/* Includes */ +/*------------------------------------------------------------------------*/ +/*------------------------------------------------------------------------*/ +/* SimIcs Includes */ +/*------------------------------------------------------------------------*/ + +/* import C functions */ + + +/*------------------------------------------------------------------------*/ +/* Forward class declaration(s) */ +/*------------------------------------------------------------------------*/ + +/*------------------------------------------------------------------------*/ +/* Macro declarations */ +/*------------------------------------------------------------------------*/ + +// definitions of MAX / MIN (if needed) +#ifndef MAX +#define MAX(a, b) ((a) > (b) ? (a) : (b)) +#endif + +#ifndef MIN +#define MIN(a, b) ((a) < (b) ? (a) : (b)) +#endif + +/* Statistics tracking definition */ +#define STAT_INC(A) (A)++ + +/*------------------------------------------------------------------------*/ +/* Enumerations */ +/*------------------------------------------------------------------------*/ + +/*------------------------------------------------------------------------*/ +/* Project Includes */ +/*------------------------------------------------------------------------*/ + +typedef unsigned char byte_t; /* byte - 8 bits */ +typedef unsigned short half_t; /* half - 16 bits */ +typedef unsigned int word_t; /* word - 32 bits */ +typedef uint64 tick_t; /* time - 64 bit */ + +#endif /* _HFATYPES_H_ */ diff --git a/src/mem/ruby/storebuffer/interface.cc b/src/mem/ruby/storebuffer/interface.cc new file mode 100644 index 000000000..1ee6ee3a0 --- /dev/null +++ b/src/mem/ruby/storebuffer/interface.cc @@ -0,0 +1,67 @@ +/* + * Copyright (c) 1999-2008 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/libruby.hh" +#include "writebuffer.hh" +#include + +writebuffer_status_t handleStore (writebuffer_t * writebuffer, const RubyRequest & request) { + assert(request.type == RubyRequestType_ST); + if (writebuffer->writeBufferFull()){ + return WB_FULL; + } + else if (writebuffer->writeBufferFlushing()) { + return WB_FLUSHING; + } + else { + writebuffer->addToWriteBuffer(request); + return WB_OK; + } +} + +uint64_t handleLoad(writebuffer_t * writebuffer, const RubyRequest & request) { + assert(request.type == RubyRequestType_LD); + return writebuffer->handleLoad(request); +} + +uint64_t handleAtomic(writebuffer_t * writebuffer, const RubyRequest & request) { + // flush the store buffer + writebuffer->flushWriteBuffer(); + // let writebuffer issue atomic + //return writebuffer->issueAtomic(request); +} + +void flushSTB(writebuffer_t * writebuffer) { + // in in-order can't get a request to flushSTB if already flushing + // on out of order, have to check if already flushing + writebuffer->flushWriteBuffer(); +} + +void registerHitCallback(writebuffer_t * writebuffer, void (*hit_callback)(int64_t access_id)) { + writebuffer->registerHitCallback(hit_callback); +} diff --git a/src/mem/ruby/storebuffer/interface.hh b/src/mem/ruby/storebuffer/interface.hh new file mode 100644 index 000000000..cbf010275 --- /dev/null +++ b/src/mem/ruby/storebuffer/interface.hh @@ -0,0 +1,46 @@ +/* + * Copyright (c) 1999-2008 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 STB_H +#define STB_H + +#include "mem/ruby/libruby.hh" +#include "writebuffer.hh" +#include + +writebuffer_status_t handleStore (writebuffer_t * writebuffer, const RubyRequest & request); + +uint64_t handleLoad(writebuffer_t * writebuffer, const RubyRequest & request); + +uint64_t handleAtomic(writebuffer_t * writebuffer, const RubyRequest & request); + +void flushSTB(writebuffer_t * writebuffer); + +void registerHitCallback(writebuffer_t * writebuffer, void (*hit_callback)(int64_t access_id)); + +#endif diff --git a/src/mem/ruby/storebuffer/stb_interface.cc b/src/mem/ruby/storebuffer/stb_interface.cc new file mode 100644 index 000000000..df280d9e1 --- /dev/null +++ b/src/mem/ruby/storebuffer/stb_interface.cc @@ -0,0 +1,73 @@ +/* + * Copyright (c) 1999-2008 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 +#include "mem/ruby/storebuffer/stb_interface.hh" + +StoreBuffer * createNewSTB(uint32 id, uint32 block_bits, int storebuffer_size) { + StoreBuffer * stb = new StoreBuffer(id, block_bits, storebuffer_size); + return stb; +} + +storebuffer_status_t handleStore (StoreBuffer * storebuffer, const RubyRequest & request) { + assert(request.type == RubyRequestType_ST); + if (storebuffer->storeBufferFull()){ + return WB_FULL; + } + else if (storebuffer->storeBufferFlushing()) { + return WB_FLUSHING; + } + else { + storebuffer->addToStoreBuffer(request); + return WB_OK; + } +} + +uint64_t handleLoad(StoreBuffer * storebuffer, const RubyRequest & request) { + assert(request.type == RubyRequestType_LD); + return storebuffer->handleLoad(request); +} + +uint64_t handleAtomic(StoreBuffer * storebuffer, const RubyRequest & request) { + // flush the store buffer + storebuffer->flushStoreBuffer(); + // let storebuffer issue atomic + //return storebuffer->issueAtomic(request); +} + +void flushSTB(StoreBuffer * storebuffer) { + // in in-order can't get a request to flushSTB if already flushing + // on out of order, have to check if already flushing + storebuffer->flushStoreBuffer(); +} + +void registerHitCallback(StoreBuffer * storebuffer, void (*hit_callback)(int64_t access_id)) { + storebuffer->registerHitCallback(hit_callback); +} + + diff --git a/src/mem/ruby/storebuffer/stb_interface.hh b/src/mem/ruby/storebuffer/stb_interface.hh new file mode 100644 index 000000000..e1a026abc --- /dev/null +++ b/src/mem/ruby/storebuffer/stb_interface.hh @@ -0,0 +1,42 @@ +/* + * Copyright (c) 1999-2008 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/storebuffer/storebuffer.hh" +#include + +StoreBuffer * createNewSTB (uint32 id, uint32 block_bits, int storebuffer_size); + +storebuffer_status_t handleStore (StoreBuffer * storebuffer, const RubyRequest & request); + +uint64_t handleLoad(StoreBuffer * storebuffer, const RubyRequest & request); + +uint64_t handleAtomic(StoreBuffer * storebuffer, const RubyRequest & request); + +void flushSTB(StoreBuffer * storebuffer); + +void registerHitCallback(StoreBuffer * storebuffer, void (*hit_callback)(int64_t access_id)); diff --git a/src/mem/ruby/storebuffer/storebuffer.cc b/src/mem/ruby/storebuffer/storebuffer.cc new file mode 100644 index 000000000..6d6e4b228 --- /dev/null +++ b/src/mem/ruby/storebuffer/storebuffer.cc @@ -0,0 +1,564 @@ +/* + * Copyright (c) 1999-2008 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. + */ + +/*------------------------------------------------------------------------*/ +/* Includes */ +/*------------------------------------------------------------------------*/ + +#include "mem/ruby/storebuffer/hfa.hh" +#include "mem/ruby/storebuffer/storebuffer.hh" +#include +#include "mem/ruby/common/Global.hh" +#include "TsoChecker.hh" + +#define SYSTEM_EXIT ASSERT(0) + + +// global map of request id_s to map them back to storebuffer pointers +map request_map; + +Tso::TsoChecker * g_tsoChecker; + +void hit(int64_t id) { + if (request_map.find(id) == request_map.end()) { + ERROR_OUT("Request ID not found in the map"); + DEBUG_EXPR(STOREBUFFER_COMP, MedPrio, id); + ASSERT(0); + } + else { + request_map[id]->complete(id); + request_map.erase(id); + } +} + + +//***************************************************************************************** +StoreBuffer::StoreBuffer(uint32 id, uint32 block_bits, int storebuffer_size) { +#ifdef TSO_CHECK + if (id == 0) { + g_tsoChecker = new Tso::TsoChecker(); + g_tsoChecker->init(64); + } +#endif + iseq = 0; + tso_iseq = 0; + char name [] = "Sequencer_"; + char port_name [13]; + sprintf(port_name, "%s%d", name, id); + m_port = libruby_get_port(port_name, hit); + m_hit_callback = NULL; + ASSERT(storebuffer_size >= 0); + m_storebuffer_size = storebuffer_size; + m_id = id; + m_block_size = 1 << block_bits; + m_block_mask = ~(m_block_size - 1); + m_buffer_size = 0; + m_use_storebuffer = false; + m_storebuffer_full = false; + m_storebuffer_flushing = false; + m_stalled_issue = true; + if(m_storebuffer_size > 0){ + m_use_storebuffer = true; + } + + #ifdef DEBUG_WRITE_BUFFER + DEBUG_OUT("*******storebuffer_t::Using Write Buffer? %d\n",m_use_storebuffer); + #endif +} + +//****************************************************************************************** +StoreBuffer::~StoreBuffer(){ +#ifdef TSO_CHECK + if (m_id == 0) { + delete g_tsoChecker; + } +#endif +} + +//***************************************************************************************************** +void StoreBuffer::registerHitCallback(void (*hit_callback)(int64_t request_id)) { + assert(m_hit_callback == NULL); // can't assign hit_callback twice + m_hit_callback = hit_callback; +} + + +//***************************************************************************************************** +void StoreBuffer::addToStoreBuffer(struct RubyRequest request){ + if(m_use_storebuffer){ + #ifdef DEBUG_WRITE_BUFFER + DEBUG_OUT("\n***StoreBuffer: addToStoreBuffer BEGIN, contents:\n"); + DEBUG_OUT("\n"); + #endif + + #ifdef DEBUG_WRITE_BUFFER + DEBUG_OUT("\t INSERTING new request\n"); + #endif + + + buffer.push_front(SBEntry(request, NULL)); + + m_buffer_size++; + + if (m_buffer_size >= m_storebuffer_size) { + m_storebuffer_full = true; + } + else if (m_stalled_issue) { + m_stalled_issue = false; + issueNextStore(); + } + + iseq++; + + #ifdef DEBUG_WRITE_BUFFER + DEBUG_OUT("***StoreBuffer: addToStoreBuffer END, contents:\n"); + DEBUG_OUT("\n"); + #endif + } //end if(m_use_storebuffer) + else { + // make request to libruby + uint64_t id = libruby_issue_request(m_port, request); + if (request_map.find(id) != request_map.end()) { + ERROR_OUT("Request ID is already in the map"); + DEBUG_EXPR(STOREBUFFER_COMP, MedPrio, id); + ASSERT(0); + } + else { + request_map.insert(make_pair(id, this)); + outstanding_requests.insert(make_pair(id, request)); + } + } +} + + +//***************************************************************************************************** +// Return value of -2 indicates that the load request was satisfied by the store buffer +// Return value of -3 indicates a partial match, so the load has to retry until NO_MATCH +// Alternatively we could satisfy the partial match, but tso gets complicated and more races +//***************************************************************************************************** +int64_t StoreBuffer::handleLoad(struct RubyRequest request) { + if (m_use_storebuffer) { + load_match match = checkForLoadHit(request); + if (match == FULL_MATCH) { + // fill data + returnMatchedData(request); + iseq++; + return -2; + } + else if (match == NO_MATCH) { + // make request to libruby and return the id + uint64_t id = libruby_issue_request(m_port, request); + if (request_map.find(id) != request_map.end()) { + ERROR_OUT("Request ID is already in the map"); + DEBUG_EXPR(STOREBUFFER_COMP, MedPrio, id); + ASSERT(0); + } + else { + request_map.insert(make_pair(id, this)); + outstanding_requests.insert(make_pair(id, request)); + } + iseq++; + return id; + } + else { // partial match + return -3; + } + } + else { + // make a request to ruby + return libruby_issue_request(m_port, request); + } +} + + +//***************************************************************************************************** +// This function will fill the data array if any match is found +//***************************************************************************************************** +load_match StoreBuffer::checkForLoadHit(struct RubyRequest request) { + if (m_use_storebuffer) { + physical_address_t physical_address = request.paddr; + int len = request.len; + + uint8_t * data = new uint8_t[64]; + memset(data, 0, 64); + for (int i = physical_address%64; i < len; i++) { + data[i] = 1; + } + + bool found = false; + physical_address_t lineaddr = physical_address & m_block_mask; + + // iterate over the buffer looking for hits + for (deque::iterator it = buffer.begin(); it != buffer.end(); it++) { + if ((it->m_request.paddr & m_block_mask) == lineaddr) { + found = true; + for (int i = it->m_request.paddr%64; i < it->m_request.len; i++) { + data[i] = 0; + } + } + } + + // if any matching entry is found, determine if all the requested bytes have been matched + if (found) { + ASSERT(m_buffer_size > 0); + int unmatched_bytes = 0; + for (int i = physical_address%64; i < len; i++) { + unmatched_bytes = unmatched_bytes + data[i]; + } + if (unmatched_bytes == 0) { + delete data; + return FULL_MATCH; + } + else { + delete data; + return PARTIAL_MATCH; + } + } + else { + delete data; + return NO_MATCH; + } + } // end of if (m_use_storebuffer) + else { + // this function should never be called if we are not using a store buffer + ERROR_OUT("checkForLoadHit called while write buffer is not in use"); + ASSERT(0); + } +} + + +//*************************************************************************************************** +void StoreBuffer::returnMatchedData(struct RubyRequest request) { + if (m_use_storebuffer) { + + uint8_t * data = new uint8_t[64]; + memset(data, 0, 64); + uint8_t * written = new uint8_t[64]; + memset(written, 0, 64); + + physical_address_t physical_address = request.paddr; + int len = request.len; + + ASSERT(checkForLoadHit(request) != NO_MATCH); + physical_address_t lineaddr = physical_address & m_block_mask; + bool found = false; + Tso::TsoCheckerCmd * cmd; + deque::iterator satisfying_store; + for (deque::iterator it = buffer.begin(); it != buffer.end(); it++) { + if ((it->m_request.paddr & m_block_mask) == lineaddr) { + if (!found) { + found = true; +#ifdef TSO_CHECK + satisfying_store = it; + cmd = new Tso::TsoCheckerCmd(m_id, // this thread id + iseq, // instruction sequence + ITYPE_LOAD, // is a store + MEM_LOAD_DATA, // commit + request.paddr, // the address + NULL, // and data + request.len, // and len + DSRC_STB, // shouldn't matter + libruby_get_time(), // macc: for store macc and time are the same and it + 0, // gobs + 0); +#endif + } + uint8_t * dataPtr = it->m_request.data; + int offset = it->m_request.paddr%64; + for (int i = offset; i < it->m_request.len; i++) { + if (!written[i]) { // don't overwrite data with earlier data + data[i] = dataPtr[i-offset]; + written[i] = 1; + } + } + } + } + + int i = physical_address%64; + for (int j = 0; (i < physical_address%64 + len) && (j < len); i++, j++) { + if (written[i]) { + request.data[j] = data[i]; + } + } + +#ifdef TSO_CHECK + uint64_t tso_data = 0; + memcpy(&tso_data, request.data, request.len); + cmd->setData(tso_data); + + Tso::TsoCheckerCmd * adjust_cmd = satisfying_store->m_next_ptr; + if (adjust_cmd == NULL) { + adjust_cmd = cmd; + } + else { + while (adjust_cmd->getNext() != NULL) { + adjust_cmd = adjust_cmd->getNext(); + } + adjust_cmd->setNext(cmd); + } +#endif + + delete data; + delete written; + } + else { + ERROR_OUT("returnMatchedData called while write buffer is not in use"); + ASSERT(0); + } +} + + +//****************************************************************************************** +void StoreBuffer::flushStoreBuffer(){ + if (m_use_storebuffer) { + #ifdef DEBUG_WRITE_BUFFER + DEBUG_OUT("\n***StoreBuffer: flushStoreBuffer BEGIN, contents:\n"); + DEBUG_OUT("\n"); + #endif + + if(m_buffer_size > 0) { + m_storebuffer_flushing = true; // indicate that we are flushing + } + else { + m_storebuffer_flushing = false; + return; + } + } + else { + // do nothing + return; + } +} + +//**************************************************************************************** +void StoreBuffer::issueNextStore() { + SBEntry request = buffer.back(); + uint64_t id = libruby_issue_request(m_port, request.m_request); + if (request_map.find(id) != request_map.end()) { + assert(0); + } + else { + request_map.insert(make_pair(id, this)); + outstanding_requests.insert(make_pair(id, request.m_request)); + } +} + +//**************************************************************************************** +void StoreBuffer::complete(uint64_t id) { + if (m_use_storebuffer) { + ASSERT(outstanding_requests.find(id) != outstanding_requests.end()); + physical_address_t physical_address = outstanding_requests.find(id)->second.paddr; + RubyRequestType type = outstanding_requests.find(id)->second.type; + int len = outstanding_requests.find(id)->second.len; +#ifdef DEBUG_WRITE_BUFFER + DEBUG_OUT("\n***StoreBuffer: complete BEGIN, contents:\n"); + DEBUG_OUT("\n"); +#endif + + if (type == RubyRequestType_ST) { + physical_address_t lineaddr = physical_address & m_block_mask; + + //Note fastpath hits are handled like regular requests - they must remove the WB entry! + if ( lineaddr != physical_address ) { + ERROR_OUT("error: StoreBuffer: ruby returns pa 0x%0llx which is not a cache line: 0x%0llx\n", physical_address, lineaddr ); + } + + SBEntry from_buffer = buffer.back(); + if (((from_buffer.m_request.paddr & m_block_mask) == lineaddr) && (from_buffer.m_request.type == type)) { + buffer.pop_back(); + m_buffer_size--; + ASSERT(m_buffer_size >= 0); + +#ifdef TSO_CHECK + uint64_t data = 0; + memcpy(&data, from_buffer.m_request.data, 4); + + cerr << m_id << " INSERTING STORE" << endl << flush; + // add to the tsoChecker + g_tsoChecker->input(m_id, // this thread id + (id & ISEQ_MASK), // instruction sequence + ITYPE_STORE, // is a store + MEM_STORE_COMMIT, // commit + physical_address, // the address + data, // and data + len, // and len + DSRC_STB, // shouldn't matter + libruby_get_time(), // macc + libruby_get_time(), // gobs + libruby_get_time()); // time + tso_iseq++; + + // also add the loads that are satisfied by this store + if (from_buffer.m_next_ptr != NULL) { + from_buffer.m_next_ptr->setGobs(libruby_get_time()); + g_tsoChecker->input(*(from_buffer.m_next_ptr)); + cerr << m_id << " INSERTING LOAD for STORE: " << from_buffer.m_next_ptr->getIseq() << endl << flush; + tso_iseq++; + Tso::TsoCheckerCmd * to_input = from_buffer.m_next_ptr->getNext(); + while (to_input != NULL) { + if (to_input->getGobs() == 0) { + to_input->setGobs(libruby_get_time()); + } + cerr << m_id << " INSERTING LOAD iseq for STORE: " << to_input->getIseq() << endl << flush; + g_tsoChecker->input(*to_input); + tso_iseq++; + to_input = to_input->getNext(); + } + } +#endif + // schedule the next request + if (m_buffer_size > 0) { + issueNextStore(); + } + else if (m_buffer_size == 0) { + m_storebuffer_flushing = false; + m_stalled_issue = true; + } + + m_storebuffer_full = false; + + } + else { + ERROR_OUT("[%d] error: StoreBuffer: at complete, address 0x%0llx not found.\n", m_id, lineaddr); + ERROR_OUT("StoreBuffer:: complete FAILS\n"); + ASSERT(0); + } + +#ifdef DEBUG_WRITE_BUFFER + DEBUG_OUT("***StoreBuffer: complete END, contents:\n"); + DEBUG_OUT("\n"); +#endif + } // end if (type == ST) + else if (type == RubyRequestType_LD) { +#ifdef TSO_CHECK + RubyRequest request = outstanding_requests.find(id)->second; + uint64_t data = 0; + memcpy(&data, request.data, request.len); + + // add to the tsoChecker if in order, otherwise, find a place to put ourselves + if ((id & ISEQ_MASK) == tso_iseq) { + tso_iseq++; + cerr << m_id << " INSERTING LOAD" << endl << flush; + g_tsoChecker->input(m_id, // this thread id + (id & ISEQ_MASK), // instruction sequence + ITYPE_LOAD, // is a store + MEM_LOAD_DATA, // commit + request.paddr, // the address + data, // and data + request.len, // and len + DSRC_L2_MEMORY, // shouldn't matter DSRC_L1 + libruby_get_time(), // macc: for store macc and time are the same and it + libruby_get_time(), // macc + libruby_get_time()); // time + } + else { + Tso::TsoCheckerCmd * cmd; + cmd = new Tso::TsoCheckerCmd(m_id, // this thread id + (id & ISEQ_MASK), // instruction sequence + ITYPE_LOAD, // is a store + MEM_LOAD_DATA, // commit + request.paddr, // the address + data, // and data + request.len, // and len + DSRC_L2_MEMORY, // shouldn't matter DSRC_L1 + libruby_get_time(), // macc: for store macc and time are the same and it + libruby_get_time(), // macc + libruby_get_time()); // time + insertTsoLL(cmd); + } +#endif + m_hit_callback(id); + } + + // LD, ST or FETCH hit callback + outstanding_requests.erase(id); + + } // end if(m_use_storebuffer) + else { + m_hit_callback(id); + } +} + + +void StoreBuffer::insertTsoLL(Tso::TsoCheckerCmd * cmd) { + uint64_t count = cmd->getIseq(); + Tso::TsoCheckerCmd * current = NULL; + Tso::TsoCheckerCmd * previous = NULL; + deque::reverse_iterator iter; + bool found = false; + for (iter = buffer.rbegin(); iter != buffer.rend(); ++ iter) { + if (iter->m_next_ptr != NULL) { + current = iter->m_next_ptr->getNext(); // initalize both to the beginning of the linked list + previous = current; + while (current != NULL) { + if (current->getIseq() > count) { + found = true; + break; + } + previous = current; + current = current->getNext(); + } + } + // break out if found a match, iterator should still point to the right SBEntry + if (found) { + break; + } + } + + // will insert at the end if not found + if (!found) { + buffer.front().m_next_ptr = cmd; + } + else if (current == previous) { + cerr << "INSERTING " << count << " BEFORE: " << iter->m_next_ptr->getIseq(); + Tso::TsoCheckerCmd * temp = iter->m_next_ptr; + iter->m_next_ptr = cmd; + cmd->setNext(temp); + } + else { + cerr << "INSERTING " << count << " BETWEEN: " << previous->getIseq() << " AND " << current->getIseq(); + cmd->setNext(current); + previous->setNext(cmd); + } +} + + +//*************************************************************************************************** +void StoreBuffer::print( void ) +{ + DEBUG_OUT("[%d] StoreBuffer: Total entries: %d Outstanding: %d\n", m_id, m_buffer_size); + + if(m_use_storebuffer){ + } + else{ + DEBUG_OUT("\t WRITE BUFFER NOT USED\n"); + } +} + + + + diff --git a/src/mem/ruby/storebuffer/storebuffer.hh b/src/mem/ruby/storebuffer/storebuffer.hh new file mode 100644 index 000000000..a5cf99f07 --- /dev/null +++ b/src/mem/ruby/storebuffer/storebuffer.hh @@ -0,0 +1,150 @@ +/* + * Copyright (c) 1999-2008 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 _STOREBUFFER_H_ +#define _STOREBUFFER_H_ + +#include +#include +#include "mem/ruby/storebuffer/hfa.hh" +#include "mem/ruby/libruby.hh" +#include "TsoCheckerCmd.hh" + +#define TSO_CHECK +/** + * Status for write buffer accesses. The Write buffer can hit in fastpath, be full, or + * successfully enqueue the store request + */ +enum storebuffer_status_t { WB_FULL, WB_OK, WB_FLUSHING }; + +/** + * Status of a load match + */ +enum load_match { NO_MATCH, PARTIAL_MATCH, FULL_MATCH }; + +struct SBEntry { + struct RubyRequest m_request; + Tso::TsoCheckerCmd * m_next_ptr; + SBEntry(struct RubyRequest request, void * ptr) { m_request = request; m_next_ptr = (Tso::TsoCheckerCmd*) ptr; } +}; + +class StoreBuffer { + public: + ///Constructor + /// Note that the size of the Write Buffer is determined by the WRITE_BUFFER_SIZE config parameter + StoreBuffer(uint32 id, uint32 block_bits, int storebuffer_size); + + /// Register hitcallback back to CPU + void registerHitCallback(void (*hit_callback)(int64_t request_id)); + + /// Destructor + ~StoreBuffer(); + + ///Adds a store entry to the write buffer + void addToStoreBuffer(struct RubyRequest request); + + ///Flushes the entire write buffer + void flushStoreBuffer(); + + ///A pseq object calls this when Ruby completes our request + void complete(uint64_t); + + /// Returns ID. If ID == -2, HIT, else it's an ID to wait on + int64_t handleLoad(struct RubyRequest request); + + /// Used by all load insts to check whether it hits to any entry in the WB. If so, the WB is flushed + load_match checkForLoadHit(struct RubyRequest request); + + /// Used to fill the load in case of FULL_MATCH + void returnMatchedData(struct RubyRequest request); + + /// Issue next store in line + void issueNextStore(); + + /// prints out the contents of the Write Buffer + void print(); + + /// if load completes before store, insert correctly to be issued to TSOChecker + void insertTsoLL(Tso::TsoCheckerCmd * cmd); + + /// Returns flag indicating whether we are using the write buffer + bool useStoreBuffer() { return m_use_storebuffer; } + + bool storeBufferFull() { return m_storebuffer_full; } + + bool storeBufferFlushing() { return m_storebuffer_flushing; } + + private: + /// id of this write buffer (one per sequencer object) + uint32 m_id; + + /// number of bytes in cacheline + uint32 m_block_size; + + /// the size of the write buffer + uint32 m_storebuffer_size; + + /// mask to strip off non-cache line bits + pa_t m_block_mask; + + /// list of store requests in the write buffer + deque buffer; + + /// the current length of the write buffer + uint32 m_buffer_size; + + /// whether we want to simulate the write buffer or not: + bool m_use_storebuffer; + + /// indicates whether the write buffer is full or not + bool m_storebuffer_full; + + /// indicates that we are currently flushing the write buffer + bool m_storebuffer_flushing; + + /// indicates that automatic issue is stalled and the next store to be added should issue itself + bool m_stalled_issue; + + /// RubyPort to make requests to + RubyPortHandle m_port; + + /// HitCallback to CPU + void (*m_hit_callback)(int64_t); + + /// Map the request id to rubyrequest + map outstanding_requests; + + /// current instruction counter + uint64_t iseq; + + + /// input into tso counter + uint64_t tso_iseq; +}; + +#endif diff --git a/src/mem/ruby/system/AbstractMemOrCache.hh b/src/mem/ruby/system/AbstractMemOrCache.hh index e56e1f505..641c117de 100644 --- a/src/mem/ruby/system/AbstractMemOrCache.hh +++ b/src/mem/ruby/system/AbstractMemOrCache.hh @@ -11,7 +11,6 @@ #define ABSTRACT_MEM_OR_CACHE_H #include "mem/ruby/common/Global.hh" -#include "mem/ruby/slicc_interface/AbstractChip.hh" #include "mem/ruby/config/RubyConfig.hh" #include "mem/ruby/common/Address.hh" diff --git a/src/mem/ruby/system/CacheMemory.hh b/src/mem/ruby/system/CacheMemory.hh index 22799ab13..4d46ac908 100644 --- a/src/mem/ruby/system/CacheMemory.hh +++ b/src/mem/ruby/system/CacheMemory.hh @@ -38,13 +38,10 @@ #ifndef CACHEMEMORY_H #define CACHEMEMORY_H -#include "mem/ruby/slicc_interface/AbstractChip.hh" #include "mem/ruby/common/Global.hh" #include "mem/protocol/AccessPermission.hh" #include "mem/ruby/common/Address.hh" - -//dsm: PRUNED -//#include "mem/ruby/recorder/CacheRecorder.hh" +#include "mem/ruby/recorder/CacheRecorder.hh" #include "mem/protocol/CacheRequestType.hh" #include "mem/gems_common/Vector.hh" #include "mem/ruby/common/DataBlock.hh" @@ -52,18 +49,25 @@ #include "mem/ruby/slicc_interface/RubySlicc_ComponentMapping.hh" #include "mem/ruby/system/PseudoLRUPolicy.hh" #include "mem/ruby/system/LRUPolicy.hh" +#include "mem/ruby/slicc_interface/AbstractCacheEntry.hh" +#include "mem/ruby/system/System.hh" +#include "mem/ruby/slicc_interface/AbstractController.hh" #include -template class CacheMemory { public: // Constructors - CacheMemory(AbstractChip* chip_ptr, int numSetBits, int cacheAssoc, const MachineType machType, const string& description); + CacheMemory(const string & name); + void init(const vector & argv); // Destructor ~CacheMemory(); + // factory + // static CacheMemory* createCache(int level, int num, char split_type, AbstractCacheEntry* (*entry_factory)()); + // static CacheMemory* getCache(int cache_id); + // Public Methods void printConfig(ostream& out); @@ -82,7 +86,7 @@ public: bool cacheAvail(const Address& address) const; // find an unused entry and sets the tag appropriate for the address - void allocate(const Address& address); + void allocate(const Address& address, AbstractCacheEntry* new_entry); // Explicitly free up this address void deallocate(const Address& address); @@ -91,16 +95,18 @@ public: Address cacheProbe(const Address& address) const; // looks an address up in the cache - ENTRY& lookup(const Address& address); - const ENTRY& lookup(const Address& address) const; + AbstractCacheEntry& lookup(const Address& address); + const AbstractCacheEntry& lookup(const Address& address) const; // Get/Set permission of cache block AccessPermission getPermission(const Address& address) const; void changePermission(const Address& address, AccessPermission new_perm); + int getLatency() const { return m_latency; } + // Hook for checkpointing the contents of the cache void recordCacheContents(CacheRecorder& tr) const; - void setAsInstructionCache(bool is_icache) { m_is_instruction_cache = is_icache; } + void setAsInstructionCache(bool is_icache) { m_is_instruction_only_cache = is_icache; } // Set this address to most recently used void setMRU(const Address& address); @@ -129,15 +135,18 @@ private: CacheMemory(const CacheMemory& obj); CacheMemory& operator=(const CacheMemory& obj); +private: + const string m_cache_name; + AbstractController* m_controller; + int m_latency; + // Data Members (m_prefix) - AbstractChip* m_chip_ptr; - MachineType m_machType; - string m_description; - bool m_is_instruction_cache; + bool m_is_instruction_only_cache; + bool m_is_data_only_cache; // The first index is the # of cache lines. // The second index is the the amount associativity. - Vector > m_cache; + Vector > m_cache; AbstractReplacementPolicy *m_replacementPolicy_ptr; @@ -145,18 +154,55 @@ private: int m_cache_num_set_bits; int m_cache_assoc; - bool is_locked; // for LL/SC + static Vector< CacheMemory* > m_all_caches; }; +/* +inline +CacheMemory* CacheMemory::getCache(int cache_id) +{ + assert(cache_id < RubyConfig::getNumberOfCaches()); + if (m_all_caches[cache_id] == NULL) { + cerr << "ERROR: Tried to obtain CacheMemory that hasn't been created yet." << endl; + assert(0); + } + return m_all_caches[cache_id]; +} +inline +CacheMemory* CacheMemory::createCache(int level, int num, char split_type_c, AbstractCacheEntry* (*entry_factory)()) +{ + string split_type; + switch(split_type_c) { + case 'i': + split_type = "instruction"; break; + case 'd': + split_type = "data"; break; + default: + split_type = "unified"; break; + } + int cache_id = RubyConfig::getCacheIDFromParams(level, num, split_type); + assert(cache_id < RubyConfig::getNumberOfCaches()); + if (m_all_caches.size() == 0) { + m_all_caches.setSize(RubyConfig::getNumberOfCaches()); + for (int i=0; i& obj); // ******************* Definitions ******************* // Output operator definition -template inline -ostream& operator<<(ostream& out, const CacheMemory& obj) +ostream& operator<<(ostream& out, const CacheMemory& obj) { obj.print(out); out << flush; @@ -166,112 +212,142 @@ ostream& operator<<(ostream& out, const CacheMemory& obj) // **************************************************************** -template inline -CacheMemory::CacheMemory(AbstractChip* chip_ptr, int numSetBits, - int cacheAssoc, const MachineType machType, const string& description) +CacheMemory::CacheMemory(const string & name) + : m_cache_name(name) +{ +} +inline +void CacheMemory::init(const vector & argv) { - //cout << "CacheMemory constructor numThreads = " << numThreads << endl; - m_chip_ptr = chip_ptr; - m_machType = machType; - m_description = MachineType_to_string(m_machType)+"_"+description; - m_cache_num_set_bits = numSetBits; - m_cache_num_sets = 1 << numSetBits; - m_cache_assoc = cacheAssoc; - m_is_instruction_cache = false; + int cache_size = 0; + string policy; + + m_controller = NULL; + for (uint32 i=0; i +*/ inline -CacheMemory::~CacheMemory() +CacheMemory::~CacheMemory() { if(m_replacementPolicy_ptr != NULL) delete m_replacementPolicy_ptr; } -template inline -void CacheMemory::printConfig(ostream& out) +void CacheMemory::printConfig(ostream& out) { - out << "Cache config: " << m_description << endl; + out << "Cache config: " << m_cache_name << endl; + if (m_controller != NULL) + out << " controller: " << m_controller->getName() << endl; out << " cache_associativity: " << m_cache_assoc << endl; out << " num_cache_sets_bits: " << m_cache_num_set_bits << endl; const int cache_num_sets = 1 << m_cache_num_set_bits; out << " num_cache_sets: " << cache_num_sets << endl; - out << " cache_set_size_bytes: " << cache_num_sets * RubyConfig::dataBlockBytes() << endl; + out << " cache_set_size_bytes: " << cache_num_sets * RubySystem::getBlockSizeBytes() << endl; out << " cache_set_size_Kbytes: " - << double(cache_num_sets * RubyConfig::dataBlockBytes()) / (1<<10) << endl; + << double(cache_num_sets * RubySystem::getBlockSizeBytes()) / (1<<10) << endl; out << " cache_set_size_Mbytes: " - << double(cache_num_sets * RubyConfig::dataBlockBytes()) / (1<<20) << endl; + << double(cache_num_sets * RubySystem::getBlockSizeBytes()) / (1<<20) << endl; out << " cache_size_bytes: " - << cache_num_sets * RubyConfig::dataBlockBytes() * m_cache_assoc << endl; + << cache_num_sets * RubySystem::getBlockSizeBytes() * m_cache_assoc << endl; out << " cache_size_Kbytes: " - << double(cache_num_sets * RubyConfig::dataBlockBytes() * m_cache_assoc) / (1<<10) << endl; + << double(cache_num_sets * RubySystem::getBlockSizeBytes() * m_cache_assoc) / (1<<10) << endl; out << " cache_size_Mbytes: " - << double(cache_num_sets * RubyConfig::dataBlockBytes() * m_cache_assoc) / (1<<20) << endl; + << double(cache_num_sets * RubySystem::getBlockSizeBytes() * m_cache_assoc) / (1<<20) << endl; } // PRIVATE METHODS // convert a Address to its location in the cache -template inline -Index CacheMemory::addressToCacheSet(const Address& address) const +Index CacheMemory::addressToCacheSet(const Address& address) const { assert(address == line_address(address)); Index temp = -1; - switch (m_machType) { - case MACHINETYPE_L1CACHE_ENUM: - temp = map_address_to_L1CacheSet(address, m_cache_num_set_bits); - break; - case MACHINETYPE_L2CACHE_ENUM: - temp = map_address_to_L2CacheSet(address, m_cache_num_set_bits); - break; - default: - ERROR_MSG("Don't recognize m_machType"); - } - assert(temp < m_cache_num_sets); - assert(temp >= 0); - return temp; + return address.bitSelect(RubySystem::getBlockSizeBits(), RubySystem::getBlockSizeBits() + m_cache_num_set_bits-1); } // Given a cache index: returns the index of the tag in a set. // returns -1 if the tag is not found. -template inline -int CacheMemory::findTagInSet(Index cacheSet, const Address& tag) const +int CacheMemory::findTagInSet(Index cacheSet, const Address& tag) const { assert(tag == line_address(tag)); // search the set for the tags for (int i=0; i < m_cache_assoc; i++) { - if ((m_cache[cacheSet][i].m_Address == tag) && - (m_cache[cacheSet][i].m_Permission != AccessPermission_NotPresent)) { + if ((m_cache[cacheSet][i] != NULL) && + (m_cache[cacheSet][i]->m_Address == tag) && + (m_cache[cacheSet][i]->m_Permission != AccessPermission_NotPresent)) { return i; } } @@ -280,39 +356,37 @@ int CacheMemory::findTagInSet(Index cacheSet, const Address& tag) const // Given a cache index: returns the index of the tag in a set. // returns -1 if the tag is not found. -template inline -int CacheMemory::findTagInSetIgnorePermissions(Index cacheSet, const Address& tag) const +int CacheMemory::findTagInSetIgnorePermissions(Index cacheSet, const Address& tag) const { assert(tag == line_address(tag)); // search the set for the tags for (int i=0; i < m_cache_assoc; i++) { - if (m_cache[cacheSet][i].m_Address == tag) + if (m_cache[cacheSet][i] != NULL && m_cache[cacheSet][i]->m_Address == tag) return i; } return -1; // Not found } // PUBLIC METHODS -template inline -bool CacheMemory::tryCacheAccess(const Address& address, - CacheRequestType type, - DataBlock*& data_ptr) +bool CacheMemory::tryCacheAccess(const Address& address, + CacheRequestType type, + DataBlock*& data_ptr) { assert(address == line_address(address)); DEBUG_EXPR(CACHE_COMP, HighPrio, address); Index cacheSet = addressToCacheSet(address); int loc = findTagInSet(cacheSet, address); if(loc != -1){ // Do we even have a tag match? - ENTRY& entry = m_cache[cacheSet][loc]; + AbstractCacheEntry* entry = m_cache[cacheSet][loc]; m_replacementPolicy_ptr->touch(cacheSet, loc, g_eventQueue_ptr->getTime()); - data_ptr = &(entry.getDataBlk()); + data_ptr = &(entry->getDataBlk()); - if(entry.m_Permission == AccessPermission_Read_Write) { + if(entry->m_Permission == AccessPermission_Read_Write) { return true; } - if ((entry.m_Permission == AccessPermission_Read_Only) && + if ((entry->m_Permission == AccessPermission_Read_Only) && (type == CacheRequestType_LD || type == CacheRequestType_IFETCH)) { return true; } @@ -322,31 +396,29 @@ bool CacheMemory::tryCacheAccess(const Address& address, return false; } -template inline -bool CacheMemory::testCacheAccess(const Address& address, - CacheRequestType type, - DataBlock*& data_ptr) +bool CacheMemory::testCacheAccess(const Address& address, + CacheRequestType type, + DataBlock*& data_ptr) { assert(address == line_address(address)); DEBUG_EXPR(CACHE_COMP, HighPrio, address); Index cacheSet = addressToCacheSet(address); int loc = findTagInSet(cacheSet, address); if(loc != -1){ // Do we even have a tag match? - ENTRY& entry = m_cache[cacheSet][loc]; + AbstractCacheEntry* entry = m_cache[cacheSet][loc]; m_replacementPolicy_ptr->touch(cacheSet, loc, g_eventQueue_ptr->getTime()); - data_ptr = &(entry.getDataBlk()); + data_ptr = &(entry->getDataBlk()); - return (m_cache[cacheSet][loc].m_Permission != AccessPermission_NotPresent); + return (m_cache[cacheSet][loc]->m_Permission != AccessPermission_NotPresent); } data_ptr = NULL; return false; } // tests to see if an address is present in the cache -template inline -bool CacheMemory::isTagPresent(const Address& address) const +bool CacheMemory::isTagPresent(const Address& address) const { assert(address == line_address(address)); Index cacheSet = addressToCacheSet(address); @@ -366,31 +438,29 @@ bool CacheMemory::isTagPresent(const Address& address) const // Returns true if there is: // a) a tag match on this address or there is // b) an unused line in the same cache "way" -template inline -bool CacheMemory::cacheAvail(const Address& address) const +bool CacheMemory::cacheAvail(const Address& address) const { assert(address == line_address(address)); Index cacheSet = addressToCacheSet(address); for (int i=0; i < m_cache_assoc; i++) { - if (m_cache[cacheSet][i].m_Address == address) { - // Already in the cache - return true; - } - - if (m_cache[cacheSet][i].m_Permission == AccessPermission_NotPresent) { - // We found an empty entry + AbstractCacheEntry* entry = m_cache[cacheSet][i]; + if (entry != NULL) { + if (entry->m_Address == address || // Already in the cache + entry->m_Permission == AccessPermission_NotPresent) { // We found an empty entry + return true; + } + } else { return true; } } return false; } -template inline -void CacheMemory::allocate(const Address& address) +void CacheMemory::allocate(const Address& address, AbstractCacheEntry* entry) { assert(address == line_address(address)); assert(!isTagPresent(address)); @@ -400,10 +470,11 @@ void CacheMemory::allocate(const Address& address) // Find the first open slot Index cacheSet = addressToCacheSet(address); for (int i=0; i < m_cache_assoc; i++) { - if (m_cache[cacheSet][i].m_Permission == AccessPermission_NotPresent) { - m_cache[cacheSet][i] = ENTRY(); // Init entry - m_cache[cacheSet][i].m_Address = address; - m_cache[cacheSet][i].m_Permission = AccessPermission_Invalid; + if (m_cache[cacheSet][i] == NULL || + m_cache[cacheSet][i]->m_Permission == AccessPermission_NotPresent) { + m_cache[cacheSet][i] = entry; // Init entry + m_cache[cacheSet][i]->m_Address = address; + m_cache[cacheSet][i]->m_Permission = AccessPermission_Invalid; m_replacementPolicy_ptr->touch(cacheSet, i, g_eventQueue_ptr->getTime()); @@ -413,63 +484,62 @@ void CacheMemory::allocate(const Address& address) ERROR_MSG("Allocate didn't find an available entry"); } -template inline -void CacheMemory::deallocate(const Address& address) +void CacheMemory::deallocate(const Address& address) { assert(address == line_address(address)); assert(isTagPresent(address)); DEBUG_EXPR(CACHE_COMP, HighPrio, address); - lookup(address).m_Permission = AccessPermission_NotPresent; + Index cacheSet = addressToCacheSet(address); + int location = findTagInSet(cacheSet, address); + if (location != -1){ + delete m_cache[cacheSet][location]; + m_cache[cacheSet][location] = NULL; + } } // Returns with the physical address of the conflicting cache line -template inline -Address CacheMemory::cacheProbe(const Address& address) const +Address CacheMemory::cacheProbe(const Address& address) const { assert(address == line_address(address)); assert(!cacheAvail(address)); Index cacheSet = addressToCacheSet(address); - return m_cache[cacheSet][m_replacementPolicy_ptr->getVictim(cacheSet)].m_Address; + return m_cache[cacheSet][m_replacementPolicy_ptr->getVictim(cacheSet)]->m_Address; } // looks an address up in the cache -template inline -ENTRY& CacheMemory::lookup(const Address& address) +AbstractCacheEntry& CacheMemory::lookup(const Address& address) { assert(address == line_address(address)); Index cacheSet = addressToCacheSet(address); int loc = findTagInSet(cacheSet, address); assert(loc != -1); - return m_cache[cacheSet][loc]; + return *m_cache[cacheSet][loc]; } // looks an address up in the cache -template inline -const ENTRY& CacheMemory::lookup(const Address& address) const +const AbstractCacheEntry& CacheMemory::lookup(const Address& address) const { assert(address == line_address(address)); Index cacheSet = addressToCacheSet(address); int loc = findTagInSet(cacheSet, address); assert(loc != -1); - return m_cache[cacheSet][loc]; + return *m_cache[cacheSet][loc]; } -template inline -AccessPermission CacheMemory::getPermission(const Address& address) const +AccessPermission CacheMemory::getPermission(const Address& address) const { assert(address == line_address(address)); return lookup(address).m_Permission; } -template inline -void CacheMemory::changePermission(const Address& address, AccessPermission new_perm) +void CacheMemory::changePermission(const Address& address, AccessPermission new_perm) { assert(address == line_address(address)); lookup(address).m_Permission = new_perm; @@ -477,9 +547,8 @@ void CacheMemory::changePermission(const Address& address, AccessPermissi } // Sets the most recently used bit for a cache block -template inline -void CacheMemory::setMRU(const Address& address) +void CacheMemory::setMRU(const Address& address) { Index cacheSet; @@ -489,19 +558,15 @@ void CacheMemory::setMRU(const Address& address) g_eventQueue_ptr->getTime()); } -template inline -void CacheMemory::recordCacheContents(CacheRecorder& tr) const +void CacheMemory::recordCacheContents(CacheRecorder& tr) const { -//dsm: Uses CacheRecorder, PRUNED -assert(false); - -/* for (int i = 0; i < m_cache_num_sets; i++) { + for (int i = 0; i < m_cache_num_sets; i++) { for (int j = 0; j < m_cache_assoc; j++) { - AccessPermission perm = m_cache[i][j].m_Permission; + AccessPermission perm = m_cache[i][j]->m_Permission; CacheRequestType request_type = CacheRequestType_NULL; if (perm == AccessPermission_Read_Only) { - if (m_is_instruction_cache) { + if (m_is_instruction_only_cache) { request_type = CacheRequestType_IFETCH; } else { request_type = CacheRequestType_LD; @@ -511,55 +576,59 @@ assert(false); } if (request_type != CacheRequestType_NULL) { - tr.addRecord(m_chip_ptr->getID(), m_cache[i][j].m_Address, - Address(0), request_type, m_replacementPolicy_ptr->getLastAccess(i, j)); + // tr.addRecord(m_chip_ptr->getID(), m_cache[i][j].m_Address, + // Address(0), request_type, m_replacementPolicy_ptr->getLastAccess(i, j)); } } - }*/ + } } -template inline -void CacheMemory::print(ostream& out) const +void CacheMemory::print(ostream& out) const { - out << "Cache dump: " << m_description << endl; + out << "Cache dump: " << m_cache_name << endl; for (int i = 0; i < m_cache_num_sets; i++) { for (int j = 0; j < m_cache_assoc; j++) { - out << " Index: " << i - << " way: " << j - << " entry: " << m_cache[i][j] << endl; + if (m_cache[i][j] != NULL) { + out << " Index: " << i + << " way: " << j + << " entry: " << *m_cache[i][j] << endl; + } else { + out << " Index: " << i + << " way: " << j + << " entry: NULL" << endl; + } } } } -template inline -void CacheMemory::printData(ostream& out) const +void CacheMemory::printData(ostream& out) const { out << "printData() not supported" << endl; } -template -void CacheMemory::getMemoryValue(const Address& addr, char* value, - unsigned int size_in_bytes ){ - ENTRY entry = lookup(line_address(addr)); +inline +void CacheMemory::getMemoryValue(const Address& addr, char* value, + unsigned int size_in_bytes ){ + AbstractCacheEntry& entry = lookup(line_address(addr)); unsigned int startByte = addr.getAddress() - line_address(addr).getAddress(); for(unsigned int i=0; i -void CacheMemory::setMemoryValue(const Address& addr, char* value, - unsigned int size_in_bytes ){ - ENTRY& entry = lookup(line_address(addr)); +inline +void CacheMemory::setMemoryValue(const Address& addr, char* value, + unsigned int size_in_bytes ){ + AbstractCacheEntry& entry = lookup(line_address(addr)); unsigned int startByte = addr.getAddress() - line_address(addr).getAddress(); assert(size_in_bytes > 0); for(unsigned int i=0; i & argv) +{ + m_version = -1; + m_controller = NULL; + for (size_t i=0;igetMandatoryQueue(); + m_is_busy = false; +} + +int64_t DMASequencer::makeRequest(const RubyRequest & request) +{ + uint64_t paddr = request.paddr; + uint8_t* data = request.data; + int len = request.len; + bool write = false; + switch(request.type) { + case RubyRequestType_LD: + write = false; + break; + case RubyRequestType_ST: + write = true; + break; + case RubyRequestType_NULL: + case RubyRequestType_IFETCH: + case RubyRequestType_RMW: + assert(0); + } + + assert(!m_is_busy); + m_is_busy = true; + + active_request.start_paddr = paddr; + active_request.write = write; + active_request.data = data; + active_request.len = len; + active_request.bytes_completed = 0; + active_request.bytes_issued = 0; + active_request.id = makeUniqueRequestID(); + + DMARequestMsg msg; + msg.getPhysicalAddress() = Address(paddr); + msg.getType() = write ? DMARequestType_WRITE : DMARequestType_READ; + msg.getOffset() = paddr & RubyConfig::dataBlockMask(); + msg.getLen() = (msg.getOffset() + len) < RubySystem::getBlockSizeBytes() ? + (msg.getOffset() + len) : + RubySystem::getBlockSizeBytes() - msg.getOffset(); + if (write) { + msg.getType() = DMARequestType_WRITE; + msg.getDataBlk().setData(data, 0, msg.getLen()); + } else { + msg.getType() = DMARequestType_READ; + } + m_mandatory_q_ptr->enqueue(msg); + active_request.bytes_issued += msg.getLen(); + + return active_request.id; +} + +void DMASequencer::issueNext() +{ + assert(m_is_busy == true); + active_request.bytes_completed = active_request.bytes_issued; + if (active_request.len == active_request.bytes_completed) { + m_hit_callback(active_request.id); + m_is_busy = false; + return; + } + + DMARequestMsg msg; + msg.getPhysicalAddress() = Address(active_request.start_paddr + active_request.bytes_completed); + assert((msg.getPhysicalAddress().getAddress() & RubyConfig::dataBlockMask()) == 0); + msg.getOffset() = 0; + msg.getType() = active_request.write ? DMARequestType_WRITE : DMARequestType_READ; + msg.getLen() = active_request.len - active_request.bytes_completed < RubySystem::getBlockSizeBytes() ? + active_request.len - active_request.bytes_completed : + RubySystem::getBlockSizeBytes(); + if (active_request.write) { + msg.getDataBlk().setData(&active_request.data[active_request.bytes_completed], 0, msg.getLen()); + msg.getType() = DMARequestType_WRITE; + } else { + msg.getType() = DMARequestType_READ; + } + m_mandatory_q_ptr->enqueue(msg); + active_request.bytes_issued += msg.getLen(); +} + +void DMASequencer::dataCallback(const DataBlock & dblk) +{ + assert(m_is_busy == true); + int len = active_request.bytes_issued - active_request.bytes_completed; + int offset = 0; + if (active_request.bytes_completed == 0) + offset = active_request.start_paddr & RubyConfig::dataBlockMask(); + memcpy(&active_request.data[active_request.bytes_completed], dblk.getData(offset, len), len); + issueNext(); +} + +void DMASequencer::ackCallback() +{ + issueNext(); +} + +void DMASequencer::printConfig(ostream & out) +{ + +} diff --git a/src/mem/ruby/system/DMASequencer.hh b/src/mem/ruby/system/DMASequencer.hh new file mode 100644 index 000000000..2665549e3 --- /dev/null +++ b/src/mem/ruby/system/DMASequencer.hh @@ -0,0 +1,49 @@ + +#ifndef DMASEQUENCER_H +#define DMASEQUENCER_H + +#include +#include "mem/ruby/common/DataBlock.hh" +#include "mem/ruby/system/RubyPort.hh" + +struct DMARequest { + uint64_t start_paddr; + int len; + bool write; + int bytes_completed; + int bytes_issued; + uint8* data; + int64_t id; +}; + +class MessageBuffer; +class AbstractController; + +class DMASequencer :public RubyPort { +public: + DMASequencer(const string & name); + void init(const vector & argv); + /* external interface */ + int64_t makeRequest(const RubyRequest & request); + // void issueRequest(uint64_t paddr, uint8* data, int len, bool rw); + bool busy() { return m_is_busy;} + + /* SLICC callback */ + void dataCallback(const DataBlock & dblk); + void ackCallback(); + + void printConfig(std::ostream & out); + +private: + void issueNext(); + +private: + int m_version; + AbstractController* m_controller; + bool m_is_busy; + DMARequest active_request; + int num_active_requests; + MessageBuffer* m_mandatory_q_ptr; +}; + +#endif // DMACONTROLLER_H diff --git a/src/mem/ruby/system/DirectoryMemory.cc b/src/mem/ruby/system/DirectoryMemory.cc index 40b990e2d..294d57de2 100644 --- a/src/mem/ruby/system/DirectoryMemory.cc +++ b/src/mem/ruby/system/DirectoryMemory.cc @@ -37,118 +37,150 @@ */ #include "mem/ruby/system/System.hh" -#include "mem/ruby/common/Driver.hh" #include "mem/ruby/system/DirectoryMemory.hh" #include "mem/ruby/slicc_interface/RubySlicc_Util.hh" #include "mem/ruby/config/RubyConfig.hh" -#include "mem/protocol/Chip.hh" +#include "mem/ruby/slicc_interface/AbstractController.hh" +#include "mem/gems_common/util.hh" -DirectoryMemory::DirectoryMemory(Chip* chip_ptr, int version) +int DirectoryMemory::m_num_directories = 0; +int DirectoryMemory::m_num_directories_bits = 0; +int DirectoryMemory::m_total_size_bytes = 0; + +DirectoryMemory::DirectoryMemory(const string & name) + : m_name(name) { - m_chip_ptr = chip_ptr; - m_version = version; - // THIS DOESN'T SEEM TO WORK -- MRM - // m_size = RubyConfig::memoryModuleBlocks()/RubyConfig::numberOfDirectory(); - m_size = RubyConfig::memoryModuleBlocks(); - assert(m_size > 0); - /********************************************************************* - // allocates an array of directory entry pointers & sets them to NULL - m_entries = new Directory_Entry*[m_size]; - if (m_entries == NULL) { - ERROR_MSG("Directory Memory: unable to allocate memory."); +} + +void DirectoryMemory::init(const vector & argv) +{ + m_controller = NULL; + for (vector::const_iterator it = argv.begin(); it != argv.end(); it++) { + if ( (*it) == "version" ) + m_version = atoi( (*(++it)).c_str() ); + else if ( (*it) == "size_mb" ) { + m_size_bytes = atoi((*(++it)).c_str()) * (1<<20); + m_size_bits = log_int(m_size_bytes); + } else if ( (*it) == "controller" ) { + m_controller = RubySystem::getController((*(++it))); + } else + assert(0); } + assert(m_controller != NULL); - for (int i=0; i < m_size; i++) { + m_num_entries = m_size_bytes / RubySystem::getBlockSizeBytes(); + m_entries = new Directory_Entry*[m_num_entries]; + for (int i=0; i < m_num_entries; i++) m_entries[i] = NULL; - } - *///////////////////////////////////////////////////////////////////// + + m_ram = g_system_ptr->getMemoryVector(); + + m_num_directories++; + m_num_directories_bits = log_int(m_num_directories); + m_total_size_bytes += m_size_bytes; } DirectoryMemory::~DirectoryMemory() { - /********************************************************************* // free up all the directory entries - for (int i=0; i < m_size; i++) { - if (m_entries[i] != NULL) { - delete m_entries[i]; - m_entries[i] = NULL; - } - } + for (int i=0;igetName() << endl; + out << " version: " << m_version << endl; + out << " memory_bits: " << m_size_bits << endl; + out << " memory_size_bytes: " << m_size_bytes << endl; + out << " memory_size_Kbytes: " << double(m_size_bytes) / (1<<10) << endl; + out << " memory_size_Mbytes: " << double(m_size_bytes) / (1<<20) << endl; + out << " memory_size_Gbytes: " << double(m_size_bytes) / (1<<30) << endl; } // Static method -void DirectoryMemory::printConfig(ostream& out) +void DirectoryMemory::printGlobalConfig(ostream & out) +{ + out << "DirectoryMemory Global Config: " << endl; + out << " number of directory memories: " << m_num_directories << endl; + if (m_num_directories > 1) { + out << " number of selection bits: " << m_num_directories_bits << endl; + out << " selection bits: " << RubySystem::getBlockSizeBits()+m_num_directories_bits-1 + << "-" << RubySystem::getBlockSizeBits() << endl; + } + out << " total memory size bytes: " << m_total_size_bytes << endl; + out << " total memory size bits: " << log_int(m_total_size_bytes) << endl; + +} + +int DirectoryMemory::mapAddressToDirectoryVersion(PhysAddress address) { - out << "Memory config:" << endl; - out << " memory_bits: " << RubyConfig::memorySizeBits() << endl; - out << " memory_size_bytes: " << RubyConfig::memorySizeBytes() << endl; - out << " memory_size_Kbytes: " << double(RubyConfig::memorySizeBytes()) / (1<<10) << endl; - out << " memory_size_Mbytes: " << double(RubyConfig::memorySizeBytes()) / (1<<20) << endl; - out << " memory_size_Gbytes: " << double(RubyConfig::memorySizeBytes()) / (1<<30) << endl; - - out << " module_bits: " << RubyConfig::memoryModuleBits() << endl; - out << " module_size_lines: " << RubyConfig::memoryModuleBlocks() << endl; - out << " module_size_bytes: " << RubyConfig::memoryModuleBlocks() * RubyConfig::dataBlockBytes() << endl; - out << " module_size_Kbytes: " << double(RubyConfig::memoryModuleBlocks() * RubyConfig::dataBlockBytes()) / (1<<10) << endl; - out << " module_size_Mbytes: " << double(RubyConfig::memoryModuleBlocks() * RubyConfig::dataBlockBytes()) / (1<<20) << endl; + if (m_num_directories_bits == 0) return 0; + int ret = address.bitSelect(RubySystem::getBlockSizeBits(), + RubySystem::getBlockSizeBits()+m_num_directories_bits-1); + return ret; } // Public method bool DirectoryMemory::isPresent(PhysAddress address) { - return (map_Address_to_DirectoryNode(address) == m_chip_ptr->getID()*RubyConfig::numberOfDirectoryPerChip()+m_version); + bool ret = (mapAddressToDirectoryVersion(address) == m_version); + return ret; } -void DirectoryMemory::readPhysMem(uint64 address, int size, void * data) +int DirectoryMemory::mapAddressToLocalIdx(PhysAddress address) { + int ret = address.getAddress() >> (RubySystem::getBlockSizeBits() + m_num_directories_bits); + return ret; } +Directory_Entry& DirectoryMemory::lookup(PhysAddress address) +{ + assert(isPresent(address)); + Directory_Entry* entry; + int idx = mapAddressToLocalIdx(address); + entry = m_entries[idx]; + if (entry == NULL) { + entry = new Directory_Entry; + entry->getDataBlk().assign(m_ram->getBlockPtr(address)); + m_entries[idx] = entry; + } + return (*entry); +} +/* Directory_Entry& DirectoryMemory::lookup(PhysAddress address) { assert(isPresent(address)); Index index = address.memoryModuleIndex(); if (index < 0 || index > m_size) { - WARN_EXPR(m_chip_ptr->getID()); WARN_EXPR(address.getAddress()); WARN_EXPR(index); WARN_EXPR(m_size); ERROR_MSG("Directory Memory Assertion: accessing memory out of range."); } - - map::iterator iter = m_entries.find(index); - Directory_Entry* entry = m_entries.find(index)->second; + Directory_Entry* entry = m_entries[index]; // allocate the directory entry on demand. - if (iter == m_entries.end()) { + if (entry == NULL) { entry = new Directory_Entry; + entry->getDataBlk().assign(m_ram->getBlockPtr(address)); - // entry->getProcOwner() = m_chip_ptr->getID(); // FIXME - This should not be hard coded - // entry->getDirOwner() = true; // FIXME - This should not be hard-coded - - // load the data from physicalMemory when first initalizing - physical_address_t physAddr = address.getAddress(); - int8 * dataArray = (int8 * )malloc(RubyConfig::dataBlockBytes() * sizeof(int8)); - readPhysMem(physAddr, RubyConfig::dataBlockBytes(), dataArray); - - for(int j=0; j < RubyConfig::dataBlockBytes(); j++) { - entry->getDataBlk().setByte(j, dataArray[j]); - } - DEBUG_EXPR(NODE_COMP, MedPrio,entry->getDataBlk()); // store entry to the table - m_entries.insert(make_pair(index, entry)); + m_entries[index] = entry; } + return (*entry); } +*/ -/* void DirectoryMemory::invalidateBlock(PhysAddress address) { + /* assert(isPresent(address)); Index index = address.memoryModuleIndex(); @@ -161,16 +193,11 @@ void DirectoryMemory::invalidateBlock(PhysAddress address) delete m_entries[index]; m_entries[index] = NULL; } - + */ } -*/ void DirectoryMemory::print(ostream& out) const { - out << "Directory dump: " << endl; - for(map::const_iterator it = m_entries.begin(); it != m_entries.end(); ++it) { - out << it->first << ": "; - out << *(it->second) << endl; - } + } diff --git a/src/mem/ruby/system/DirectoryMemory.hh b/src/mem/ruby/system/DirectoryMemory.hh index 6451ed459..6445ecc62 100644 --- a/src/mem/ruby/system/DirectoryMemory.hh +++ b/src/mem/ruby/system/DirectoryMemory.hh @@ -41,26 +41,34 @@ #include "mem/ruby/common/Global.hh" #include "mem/ruby/common/Address.hh" +#include "mem/ruby/system/MemoryVector.hh" #include "mem/protocol/Directory_Entry.hh" -#include -class Chip; +class AbstractController; class DirectoryMemory { public: // Constructors - DirectoryMemory(Chip* chip_ptr, int version); + DirectoryMemory(const string & name); + void init(const vector & argv); + // DirectoryMemory(int version); // Destructor ~DirectoryMemory(); + int mapAddressToLocalIdx(PhysAddress address); + static int mapAddressToDirectoryVersion(PhysAddress address); + + int getSize() { return m_size_bytes; } + // Public Methods - static void printConfig(ostream& out); + void printConfig(ostream& out) const; + static void printGlobalConfig(ostream & out); bool isPresent(PhysAddress address); - // dummy function - void readPhysMem(uint64 address, int size, void * data); Directory_Entry& lookup(PhysAddress address); + void invalidateBlock(PhysAddress address); + void print(ostream& out) const; private: @@ -70,11 +78,22 @@ private: DirectoryMemory(const DirectoryMemory& obj); DirectoryMemory& operator=(const DirectoryMemory& obj); +private: + const string m_name; + AbstractController* m_controller; // Data Members (m_ prefix) - map m_entries; - Chip* m_chip_ptr; - int m_size; // # of memory module blocks for this directory + Directory_Entry **m_entries; + // int m_size; // # of memory module blocks this directory is responsible for + uint32 m_size_bytes; + uint32 m_size_bits; + int m_num_entries; int m_version; + + static int m_num_directories; + static int m_num_directories_bits; + static int m_total_size_bytes; + + MemoryVector* m_ram; }; // Output operator declaration diff --git a/src/mem/ruby/system/MemoryControl.cc b/src/mem/ruby/system/MemoryControl.cc index 86c6526c8..f9159ed3e 100644 --- a/src/mem/ruby/system/MemoryControl.cc +++ b/src/mem/ruby/system/MemoryControl.cc @@ -110,21 +110,21 @@ * */ -#include - -#include "base/cprintf.hh" #include "mem/ruby/common/Global.hh" #include "mem/gems_common/Map.hh" #include "mem/ruby/common/Address.hh" #include "mem/ruby/profiler/Profiler.hh" -#include "mem/ruby/slicc_interface/AbstractChip.hh" #include "mem/ruby/system/System.hh" #include "mem/ruby/slicc_interface/RubySlicc_ComponentMapping.hh" #include "mem/ruby/slicc_interface/NetworkMessage.hh" #include "mem/ruby/network/Network.hh" + #include "mem/ruby/common/Consumer.hh" + #include "mem/ruby/system/MemoryControl.hh" +#include + class Consumer; // Value to reset watchdog timer to. @@ -151,32 +151,66 @@ ostream& operator<<(ostream& out, const MemoryControl& obj) // **************************************************************** // CONSTRUCTOR +MemoryControl::MemoryControl(const string & name) + : m_name(name) +{ + m_name = name; +// printf ("MemoryControl name is %s \n", m_name.c_str()); +} + +void MemoryControl::init(const vector & argv) +{ + + for (vector::const_iterator it = argv.begin(); it != argv.end(); it++) { + if ( (*it) == "version" ) + m_version = atoi( (*(++it)).c_str() ); + else if ( (*it) == "mem_bus_cycle_multiplier" ) { + m_mem_bus_cycle_multiplier = atoi((*(++it)).c_str()); + } else if ( (*it) == "banks_per_rank" ) { + m_banks_per_rank = atoi((*(++it)).c_str()); + } else if ( (*it) == "ranks_per_dimm" ) { + m_ranks_per_dimm = atoi((*(++it)).c_str()); + } else if ( (*it) == "dimms_per_channel" ) { + m_dimms_per_channel = atoi((*(++it)).c_str()); + } else if ( (*it) == "bank_bit_0" ) { + m_bank_bit_0 = atoi((*(++it)).c_str()); + } else if ( (*it) == "rank_bit_0" ) { + m_rank_bit_0 = atoi((*(++it)).c_str()); + } else if ( (*it) == "dimm_bit_0" ) { + m_dimm_bit_0 = atoi((*(++it)).c_str()); + } else if ( (*it) == "bank_queue_size" ) { + m_bank_queue_size = atoi((*(++it)).c_str()); + } else if ( (*it) == "bank_busy_time" ) { + m_bank_busy_time = atoi((*(++it)).c_str()); + } else if ( (*it) == "rank_rank_delay" ) { + m_rank_rank_delay = atoi((*(++it)).c_str()); + } else if ( (*it) == "read_write_delay" ) { + m_read_write_delay = atoi((*(++it)).c_str()); + } else if ( (*it) == "basic_bus_busy_time" ) { + m_basic_bus_busy_time = atoi((*(++it)).c_str()); + } else if ( (*it) == "mem_ctl_latency" ) { + m_mem_ctl_latency = atoi((*(++it)).c_str()); + } else if ( (*it) == "refresh_period" ) { + m_refresh_period = atoi((*(++it)).c_str()); + } else if ( (*it) == "tFaw" ) { + m_tFaw = atoi((*(++it)).c_str()); + } else if ( (*it) == "mem_random_arbitrate" ) { + m_mem_random_arbitrate = atoi((*(++it)).c_str()); + } else if ( (*it) == "mem_fixed_delay" ) { + m_mem_fixed_delay = atoi((*(++it)).c_str()); + } +// } else +// assert(0); + } + -MemoryControl::MemoryControl (AbstractChip* chip_ptr, int version) { - m_chip_ptr = chip_ptr; - m_version = version; +/////// + //m_version = version; m_msg_counter = 0; m_debug = 0; //if (m_version == 0) m_debug = 1; - m_mem_bus_cycle_multiplier = RubyConfig::memBusCycleMultiplier(); - m_banks_per_rank = RubyConfig::banksPerRank(); - m_ranks_per_dimm = RubyConfig::ranksPerDimm(); - m_dimms_per_channel = RubyConfig::dimmsPerChannel(); - m_bank_bit_0 = RubyConfig::bankBit0(); - m_rank_bit_0 = RubyConfig::rankBit0(); - m_dimm_bit_0 = RubyConfig::dimmBit0(); - m_bank_queue_size = RubyConfig::bankQueueSize(); - m_bank_busy_time = RubyConfig::bankBusyTime(); - m_rank_rank_delay = RubyConfig::rankRankDelay(); - m_read_write_delay = RubyConfig::readWriteDelay(); - m_basic_bus_busy_time = RubyConfig::basicBusBusyTime(); - m_mem_ctl_latency = RubyConfig::memCtlLatency(); - m_refresh_period = RubyConfig::refreshPeriod(); - m_memRandomArbitrate = RubyConfig::memRandomArbitrate(); - m_tFaw = RubyConfig::tFaw(); - m_memFixedDelay = RubyConfig::memFixedDelay(); assert(m_tFaw <= 62); // must fit in a uint64 shift register @@ -257,13 +291,15 @@ void MemoryControl::enqueueMemRef (MemoryNode& memRef) { Time arrival_time = memRef.m_time; uint64 at = arrival_time; bool is_mem_read = memRef.m_is_mem_read; + bool dirtyWB = memRef.m_is_dirty_wb; physical_address_t addr = memRef.m_addr; int bank = getBank(addr); if (m_debug) { - cprintf("New memory request%7d: %#08x %c arrived at %10d bank =%3x\n", - m_msg_counter, addr, is_mem_read? 'R':'W', at, bank); + printf("New memory request%7d: 0x%08llx %c arrived at %10lld ", m_msg_counter, addr, is_mem_read? 'R':'W', at); + printf("bank =%3x\n", bank); } - g_system_ptr->getProfiler()->profileMemReq(bank); +// printf ("m_name is %s \n", m_name.c_str()); + g_system_ptr->getProfiler()->profileMemReq(m_name, bank); m_input_queue.push_back(memRef); if (!m_awakened) { g_eventQueue_ptr->scheduleEvent(this, 1); @@ -295,7 +331,7 @@ MemoryNode MemoryControl::peekNode () { MemoryNode req = m_response_queue.front(); uint64 returnTime = req.m_time; if (m_debug) { - cprintf("Old memory request%7d: %#08x %c peeked at %10d\n", + printf("Old memory request%7d: 0x%08llx %c peeked at %10lld\n", req.m_msg_counter, req.m_addr, req.m_is_mem_read? 'R':'W', returnTime); } return req; @@ -319,10 +355,10 @@ void MemoryControl::printConfig (ostream& out) { out << "Memory Control " << m_version << ":" << endl; out << " Ruby cycles per memory cycle: " << m_mem_bus_cycle_multiplier << endl; out << " Basic read latency: " << m_mem_ctl_latency << endl; - if (m_memFixedDelay) { - out << " Fixed Latency mode: Added cycles = " << m_memFixedDelay << endl; + if (m_mem_fixed_delay) { + out << " Fixed Latency mode: Added cycles = " << m_mem_fixed_delay << endl; } else { - out << " Bank busy time: " << BANK_BUSY_TIME << " memory cycles" << endl; + out << " Bank busy time: " << m_bank_busy_time << " memory cycles" << endl; out << " Memory channel busy time: " << m_basic_bus_busy_time << endl; out << " Dead cycles between reads to different ranks: " << m_rank_rank_delay << endl; out << " Dead cycle between a read and a write: " << m_read_write_delay << endl; @@ -336,7 +372,7 @@ void MemoryControl::printConfig (ostream& out) { out << " LSB of DIMM field in address: " << m_dimm_bit_0 << endl; out << " Max size of each bank queue: " << m_bank_queue_size << endl; out << " Refresh period (within one bank): " << m_refresh_period << endl; - out << " Arbitration randomness: " << m_memRandomArbitrate << endl; + out << " Arbitration randomness: " << m_mem_random_arbitrate << endl; } @@ -389,20 +425,20 @@ int MemoryControl::getRank (int bank) { // can be issued this cycle bool MemoryControl::queueReady (int bank) { - if ((m_bankBusyCounter[bank] > 0) && !m_memFixedDelay) { - g_system_ptr->getProfiler()->profileMemBankBusy(); - //if (m_debug) cprintf(" bank %x busy %d\n", bank, m_bankBusyCounter[bank]); + if ((m_bankBusyCounter[bank] > 0) && !m_mem_fixed_delay) { + g_system_ptr->getProfiler()->profileMemBankBusy(m_name); + //if (m_debug) printf(" bank %x busy %d\n", bank, m_bankBusyCounter[bank]); return false; } - if (m_memRandomArbitrate >= 2) { - if ((random() % 100) < m_memRandomArbitrate) { - g_system_ptr->getProfiler()->profileMemRandBusy(); + if (m_mem_random_arbitrate >= 2) { + if ((random() % 100) < m_mem_random_arbitrate) { + g_system_ptr->getProfiler()->profileMemRandBusy(m_name); return false; } } - if (m_memFixedDelay) return true; + if (m_mem_fixed_delay) return true; if ((m_ageCounter > (2 * m_bank_busy_time)) && !m_oldRequest[bank]) { - g_system_ptr->getProfiler()->profileMemNotOld(); + g_system_ptr->getProfiler()->profileMemNotOld(m_name); return false; } if (m_busBusyCounter_Basic == m_basic_bus_busy_time) { @@ -411,26 +447,26 @@ bool MemoryControl::queueReady (int bank) { // a bus wait. This is a little inaccurate since it MIGHT // have also been blocked waiting for a read-write or a // read-read instead, but it's pretty close. - g_system_ptr->getProfiler()->profileMemArbWait(1); + g_system_ptr->getProfiler()->profileMemArbWait(m_name, 1); return false; } if (m_busBusyCounter_Basic > 0) { - g_system_ptr->getProfiler()->profileMemBusBusy(); + g_system_ptr->getProfiler()->profileMemBusBusy(m_name); return false; } int rank = getRank(bank); if (m_tfaw_count[rank] >= ACTIVATE_PER_TFAW) { - g_system_ptr->getProfiler()->profileMemTfawBusy(); + g_system_ptr->getProfiler()->profileMemTfawBusy(m_name); return false; } bool write = !m_bankQueues[bank].front().m_is_mem_read; if (write && (m_busBusyCounter_Write > 0)) { - g_system_ptr->getProfiler()->profileMemReadWriteBusy(); + g_system_ptr->getProfiler()->profileMemReadWriteBusy(m_name); return false; } if (!write && (rank != m_busBusy_WhichRank) && (m_busBusyCounter_ReadNewRank > 0)) { - g_system_ptr->getProfiler()->profileMemDataBusBusy(); + g_system_ptr->getProfiler()->profileMemDataBusBusy(m_name); return false; } return true; @@ -453,9 +489,9 @@ bool MemoryControl::issueRefresh (int bank) { //if (m_debug) { //uint64 current_time = g_eventQueue_ptr->getTime(); - //cprintf(" Refresh bank %3x at %d\n", bank, current_time); + //printf(" Refresh bank %3x at %lld\n", bank, current_time); //} - g_system_ptr->getProfiler()->profileMemRefresh(); + g_system_ptr->getProfiler()->profileMemRefresh(m_name); m_need_refresh--; m_refresh_bank++; if (m_refresh_bank >= m_total_banks) m_refresh_bank = 0; @@ -488,23 +524,23 @@ void MemoryControl::issueRequest (int bank) { m_bankQueues[bank].pop_front(); if (m_debug) { uint64 current_time = g_eventQueue_ptr->getTime(); - cprintf(" Mem issue request%7d: %#08x %c at %10d bank =%3x\n", + printf(" Mem issue request%7d: 0x%08llx %c at %10lld bank =%3x\n", req.m_msg_counter, req.m_addr, req.m_is_mem_read? 'R':'W', current_time, bank); } if (req.m_msgptr.ref() != NULL) { // don't enqueue L3 writebacks - enqueueToDirectory(req, m_mem_ctl_latency + m_memFixedDelay); + enqueueToDirectory(req, m_mem_ctl_latency + m_mem_fixed_delay); } m_oldRequest[bank] = 0; markTfaw(rank); m_bankBusyCounter[bank] = m_bank_busy_time; m_busBusy_WhichRank = rank; if (req.m_is_mem_read) { - g_system_ptr->getProfiler()->profileMemRead(); + g_system_ptr->getProfiler()->profileMemRead(m_name); m_busBusyCounter_Basic = m_basic_bus_busy_time; m_busBusyCounter_Write = m_basic_bus_busy_time + m_read_write_delay; m_busBusyCounter_ReadNewRank = m_basic_bus_busy_time + m_rank_rank_delay; } else { - g_system_ptr->getProfiler()->profileMemWrite(); + g_system_ptr->getProfiler()->profileMemWrite(m_name); m_busBusyCounter_Basic = m_basic_bus_busy_time; m_busBusyCounter_Write = m_basic_bus_busy_time; m_busBusyCounter_ReadNewRank = m_basic_bus_busy_time; @@ -531,8 +567,8 @@ void MemoryControl::executeCycle () { } // After time period expires, latch an indication that we need a refresh. - // Disable refresh if in memFixedDelay mode. - if (!m_memFixedDelay) m_refresh_count--; + // Disable refresh if in mem_fixed_delay mode. + if (!m_mem_fixed_delay) m_refresh_count--; if (m_refresh_count == 0) { m_refresh_count = m_refresh_period_system; assert (m_need_refresh < 10); // Are we overrunning our ability to refresh? @@ -553,7 +589,7 @@ void MemoryControl::executeCycle () { } // If randomness desired, re-randomize round-robin position each cycle - if (m_memRandomArbitrate) { + if (m_mem_random_arbitrate) { m_roundRobin = random() % m_total_banks; } @@ -562,7 +598,7 @@ void MemoryControl::executeCycle () { // request and issue it. Treat a refresh request as if it // were at the head of its bank queue. After we issue something, // keep scanning the queues just to gather statistics about - // how many are waiting. If in memFixedDelay mode, we can issue + // how many are waiting. If in mem_fixed_delay mode, we can issue // more than one request per cycle. int queueHeads = 0; @@ -573,7 +609,7 @@ void MemoryControl::executeCycle () { issueRefresh(m_roundRobin); int qs = m_bankQueues[m_roundRobin].size(); if (qs > 1) { - g_system_ptr->getProfiler()->profileMemBankQ(qs-1); + g_system_ptr->getProfiler()->profileMemBankQ(m_name, qs-1); } if (qs > 0) { m_idleCount = IDLECOUNT_MAX_VALUE; // we're not idle if anything is queued @@ -581,15 +617,15 @@ void MemoryControl::executeCycle () { if (queueReady(m_roundRobin)) { issueRequest(m_roundRobin); banksIssued++; - if (m_memFixedDelay) { - g_system_ptr->getProfiler()->profileMemWaitCycles(m_memFixedDelay); + if (m_mem_fixed_delay) { + g_system_ptr->getProfiler()->profileMemWaitCycles(m_name, m_mem_fixed_delay); } } } } // memWaitCycles is a redundant catch-all for the specific counters in queueReady - g_system_ptr->getProfiler()->profileMemWaitCycles(queueHeads - banksIssued); + g_system_ptr->getProfiler()->profileMemWaitCycles(m_name, queueHeads - banksIssued); // Check input queue and move anything to bank queues if not full. // Since this is done here at the end of the cycle, there will always @@ -606,7 +642,7 @@ void MemoryControl::executeCycle () { m_input_queue.pop_front(); m_bankQueues[bank].push_back(req); } - g_system_ptr->getProfiler()->profileMemInputQ(m_input_queue.size()); + g_system_ptr->getProfiler()->profileMemInputQ(m_name, m_input_queue.size()); } } diff --git a/src/mem/ruby/system/MemoryControl.hh b/src/mem/ruby/system/MemoryControl.hh index aef2edc5b..3419f8c40 100644 --- a/src/mem/ruby/system/MemoryControl.hh +++ b/src/mem/ruby/system/MemoryControl.hh @@ -43,7 +43,6 @@ #include "mem/gems_common/Map.hh" #include "mem/ruby/common/Address.hh" #include "mem/ruby/profiler/Profiler.hh" -#include "mem/ruby/slicc_interface/AbstractChip.hh" #include "mem/ruby/system/System.hh" #include "mem/ruby/slicc_interface/Message.hh" #include "mem/gems_common/util.hh" @@ -67,7 +66,8 @@ class MemoryControl : public Consumer, public AbstractMemOrCache { public: // Constructors - MemoryControl (AbstractChip* chip_ptr, int version); + MemoryControl(const string & name); + void init(const vector & argv); // Destructor ~MemoryControl (); @@ -78,8 +78,8 @@ public: void setConsumer (Consumer* consumer_ptr); Consumer* getConsumer () { return m_consumer_ptr; }; - void setDescription (const string& name) { m_name = name; }; - string getDescription () { return m_name; }; + void setDescription (const string& name) { m_description = name; }; + string getDescription () { return m_description; }; // Called from the directory: void enqueue (const MsgPtr& message, int latency ); @@ -97,6 +97,12 @@ public: void print (ostream& out) const; void setDebug (int debugFlag); + + //added by SS + int getBanksPerRank() { return m_banks_per_rank; }; + int getRanksPerDimm() { return m_ranks_per_dimm; }; + int getDimmsPerChannel() { return m_dimms_per_channel; } + private: void enqueueToDirectory (MemoryNode req, int latency); @@ -113,9 +119,9 @@ private: MemoryControl& operator=(const MemoryControl& obj); // data members - AbstractChip* m_chip_ptr; Consumer* m_consumer_ptr; // Consumer to signal a wakeup() string m_name; + string m_description; int m_version; int m_msg_counter; int m_awakened; @@ -134,9 +140,9 @@ private: int m_basic_bus_busy_time; int m_mem_ctl_latency; int m_refresh_period; - int m_memRandomArbitrate; + int m_mem_random_arbitrate; int m_tFaw; - int m_memFixedDelay; + int m_mem_fixed_delay; int m_total_banks; int m_total_ranks; diff --git a/src/mem/ruby/system/MemoryVector.hh b/src/mem/ruby/system/MemoryVector.hh new file mode 100644 index 000000000..c5f3cea7f --- /dev/null +++ b/src/mem/ruby/system/MemoryVector.hh @@ -0,0 +1,81 @@ + +#ifndef MEMORYVECTOR_H +#define MEMORYVECTOR_H + +#include "mem/ruby/common/Address.hh" + +class DirectoryMemory; + +/** + * MemoryVector holds memory data (DRAM only) + */ +class MemoryVector { + public: + MemoryVector(); + MemoryVector(uint32 size); + ~MemoryVector(); + friend class DirectoryMemory; + + void setSize(uint32 size); // destructive + + void write(const Address & paddr, uint8* data, int len); + uint8* read(const Address & paddr, uint8* data, int len); + + private: + uint8* getBlockPtr(const Address & paddr); + + uint32 m_size; + uint8* m_vec; +}; + +inline +MemoryVector::MemoryVector() +{ + m_size = 0; + m_vec = NULL; +} + +inline +MemoryVector::MemoryVector(uint32 size) +{ + m_size = size; + m_vec = new uint8[size]; +} + +inline +MemoryVector::~MemoryVector() +{ + delete [] m_vec; +} + +inline +void MemoryVector::setSize(uint32 size) +{ + m_size = size; + if (m_vec != NULL) + delete [] m_vec; + m_vec = new uint8[size]; +} + +inline +void MemoryVector::write(const Address & paddr, uint8* data, int len) +{ + assert(paddr.getAddress() + len <= m_size); + memcpy(m_vec + paddr.getAddress(), data, len); +} + +inline +uint8* MemoryVector::read(const Address & paddr, uint8* data, int len) +{ + assert(paddr.getAddress() + len <= m_size); + memcpy(data, m_vec + paddr.getAddress(), len); + return data; +} + +inline +uint8* MemoryVector::getBlockPtr(const Address & paddr) +{ + return m_vec + paddr.getAddress(); +} + +#endif // MEMORYVECTOR_H diff --git a/src/mem/ruby/system/NodePersistentTable.cc b/src/mem/ruby/system/NodePersistentTable.cc deleted file mode 100644 index 4dd5c670f..000000000 --- a/src/mem/ruby/system/NodePersistentTable.cc +++ /dev/null @@ -1,193 +0,0 @@ - -/* - * Copyright (c) 1999-2008 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. - */ - -/* - * $Id: NodePersistentTable.C 1.3 04/08/16 14:12:33-05:00 beckmann@c2-143.cs.wisc.edu $ - * - */ - -#include "mem/ruby/system/NodePersistentTable.hh" -#include "mem/ruby/common/Set.hh" -#include "mem/gems_common/Map.hh" -#include "mem/ruby/common/Address.hh" -#include "mem/ruby/slicc_interface/AbstractChip.hh" -#include "mem/gems_common/util.hh" - -// randomize so that handoffs are not locality-aware -// int persistent_randomize[] = {0, 4, 8, 12, 1, 5, 9, 13, 2, 6, 10, 14, 3, 7, 11, 15}; -int persistent_randomize[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}; - - -class NodePersistentTableEntry { -public: - Set m_starving; - Set m_marked; - Set m_request_to_write; -}; - -NodePersistentTable::NodePersistentTable(AbstractChip* chip_ptr, int version) -{ - m_chip_ptr = chip_ptr; - m_map_ptr = new Map; - m_version = version; -} - -NodePersistentTable::~NodePersistentTable() -{ - delete m_map_ptr; - m_map_ptr = NULL; - m_chip_ptr = NULL; -} - -void NodePersistentTable::persistentRequestLock(const Address& address, NodeID llocker, AccessType type) -{ - - // if (locker == m_chip_ptr->getID() ) - // cout << "Chip " << m_chip_ptr->getID() << ": " << llocker << " requesting lock for " << address << endl; - - NodeID locker = (NodeID) persistent_randomize[llocker]; - - assert(address == line_address(address)); - if (!m_map_ptr->exist(address)) { - // Allocate if not present - NodePersistentTableEntry entry; - entry.m_starving.add(locker); - if (type == AccessType_Write) { - entry.m_request_to_write.add(locker); - } - m_map_ptr->add(address, entry); - } else { - NodePersistentTableEntry& entry = m_map_ptr->lookup(address); - assert(!(entry.m_starving.isElement(locker))); // Make sure we're not already in the locked set - - entry.m_starving.add(locker); - if (type == AccessType_Write) { - entry.m_request_to_write.add(locker); - } - assert(entry.m_marked.isSubset(entry.m_starving)); - } -} - -void NodePersistentTable::persistentRequestUnlock(const Address& address, NodeID uunlocker) -{ - // if (unlocker == m_chip_ptr->getID() ) - // cout << "Chip " << m_chip_ptr->getID() << ": " << uunlocker << " requesting unlock for " << address << endl; - - NodeID unlocker = (NodeID) persistent_randomize[uunlocker]; - - assert(address == line_address(address)); - assert(m_map_ptr->exist(address)); - NodePersistentTableEntry& entry = m_map_ptr->lookup(address); - assert(entry.m_starving.isElement(unlocker)); // Make sure we're in the locked set - assert(entry.m_marked.isSubset(entry.m_starving)); - entry.m_starving.remove(unlocker); - entry.m_marked.remove(unlocker); - entry.m_request_to_write.remove(unlocker); - assert(entry.m_marked.isSubset(entry.m_starving)); - - // Deallocate if empty - if (entry.m_starving.isEmpty()) { - assert(entry.m_marked.isEmpty()); - m_map_ptr->erase(address); - } -} - -bool NodePersistentTable::okToIssueStarving(const Address& address) const -{ - assert(address == line_address(address)); - if (!m_map_ptr->exist(address)) { - return true; // No entry present - } else if (m_map_ptr->lookup(address).m_starving.isElement(m_chip_ptr->getID())) { - return false; // We can't issue another lockdown until are previous unlock has occurred - } else { - return (m_map_ptr->lookup(address).m_marked.isEmpty()); - } -} - -NodeID NodePersistentTable::findSmallest(const Address& address) const -{ - assert(address == line_address(address)); - assert(m_map_ptr->exist(address)); - const NodePersistentTableEntry& entry = m_map_ptr->lookup(address); - // cout << "Node " << m_chip_ptr->getID() << " returning " << persistent_randomize[entry.m_starving.smallestElement()] << " for findSmallest(" << address << ")" << endl; - return (NodeID) persistent_randomize[entry.m_starving.smallestElement()]; -} - -AccessType NodePersistentTable::typeOfSmallest(const Address& address) const -{ - assert(address == line_address(address)); - assert(m_map_ptr->exist(address)); - const NodePersistentTableEntry& entry = m_map_ptr->lookup(address); - if (entry.m_request_to_write.isElement(entry.m_starving.smallestElement())) { - return AccessType_Write; - } else { - return AccessType_Read; - } -} - -void NodePersistentTable::markEntries(const Address& address) -{ - assert(address == line_address(address)); - if (m_map_ptr->exist(address)) { - NodePersistentTableEntry& entry = m_map_ptr->lookup(address); - assert(entry.m_marked.isEmpty()); // None should be marked - entry.m_marked = entry.m_starving; // Mark all the nodes currently in the table - } -} - -bool NodePersistentTable::isLocked(const Address& address) const -{ - assert(address == line_address(address)); - // If an entry is present, it must be locked - return (m_map_ptr->exist(address)); -} - -int NodePersistentTable::countStarvingForAddress(const Address& address) const -{ - if (m_map_ptr->exist(address)) { - NodePersistentTableEntry& entry = m_map_ptr->lookup(address); - return (entry.m_starving.count()); - } - else { - return 0; - } -} - -int NodePersistentTable::countReadStarvingForAddress(const Address& address) const -{ - if (m_map_ptr->exist(address)) { - NodePersistentTableEntry& entry = m_map_ptr->lookup(address); - return (entry.m_starving.count() - entry.m_request_to_write.count()); - } - else { - return 0; - } -} - - diff --git a/src/mem/ruby/system/NodePersistentTable.hh b/src/mem/ruby/system/NodePersistentTable.hh deleted file mode 100644 index d731b25ae..000000000 --- a/src/mem/ruby/system/NodePersistentTable.hh +++ /dev/null @@ -1,99 +0,0 @@ - -/* - * Copyright (c) 1999-2008 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. - */ - -/* - * $Id: NodePersistentTable.hh 1.3 04/08/16 14:12:33-05:00 beckmann@c2-143.cs.wisc.edu $ - * - * Description: - * - */ - -#ifndef NodePersistentTable_H -#define NodePersistentTable_H - -#include "mem/ruby/common/Global.hh" -#include "mem/ruby/system/NodeID.hh" -#include "mem/protocol/AccessType.hh" - -class AbstractChip; - -template class Map; -class Address; -class NodePersistentTableEntry; - -class NodePersistentTable { -public: - // Constructors - NodePersistentTable(AbstractChip* chip_ptr, int version); - - // Destructor - ~NodePersistentTable(); - - // Public Methods - void persistentRequestLock(const Address& address, NodeID locker, AccessType type); - void persistentRequestUnlock(const Address& address, NodeID unlocker); - bool okToIssueStarving(const Address& address) const; - NodeID findSmallest(const Address& address) const; - AccessType typeOfSmallest(const Address& address) const; - void markEntries(const Address& address); - bool isLocked(const Address& addr) const; - int countStarvingForAddress(const Address& addr) const; - int countReadStarvingForAddress(const Address& addr) const; - - static void printConfig(ostream& out) {} - - void print(ostream& out) const; -private: - // Private Methods - - // Private copy constructor and assignment operator - NodePersistentTable(const NodePersistentTable& obj); - NodePersistentTable& operator=(const NodePersistentTable& obj); - - // Data Members (m_prefix) - Map* m_map_ptr; - AbstractChip* m_chip_ptr; - int m_version; -}; - -// Output operator declaration -ostream& operator<<(ostream& out, const NodePersistentTable& obj); - -// ******************* Definitions ******************* - -// Output operator definition -extern inline -ostream& operator<<(ostream& out, const NodePersistentTable& obj) -{ - obj.print(out); - out << flush; - return out; -} - -#endif //NodePersistentTable_H diff --git a/src/mem/ruby/system/PersistentArbiter.cc b/src/mem/ruby/system/PersistentArbiter.cc deleted file mode 100644 index b44393301..000000000 --- a/src/mem/ruby/system/PersistentArbiter.cc +++ /dev/null @@ -1,165 +0,0 @@ - -/* - * Copyright (c) 1999-2008 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/system/PersistentArbiter.hh" -#include "mem/ruby/common/Address.hh" -#include "mem/ruby/slicc_interface/AbstractChip.hh" -#include "mem/gems_common/util.hh" - -PersistentArbiter::PersistentArbiter(AbstractChip* chip_ptr) -{ - m_chip_ptr = chip_ptr; - - // wastes entries, but who cares - m_entries.setSize(RubyConfig::numberOfProcessors()); - - for (int i = 0; i < m_entries.size(); i++) { - m_entries[i].valid = false; - } - - m_busy = false; - m_locker = -1; - -} - -PersistentArbiter::~PersistentArbiter() -{ - m_chip_ptr = NULL; -} - - -void PersistentArbiter::addLocker(NodeID id, Address addr, AccessType type) { - //cout << "Arbiter " << getArbiterId() << " adding locker " << id << " " << addr << endl; - assert(m_entries[id].valid == false); - m_entries[id].valid = true; - m_entries[id].address = addr; - m_entries[id].type = type; - m_entries[id].localId = id; - -} - -void PersistentArbiter::removeLocker(NodeID id) { - //cout << "Arbiter " << getArbiterId() << " removing locker " << id << " " << m_entries[id].address << endl; - assert(m_entries[id].valid == true); - m_entries[id].valid = false; - - if (!lockersExist()) { - m_busy = false; - } -} - -bool PersistentArbiter::successorRequestPresent(Address addr, NodeID id) { - for (int i = (id + 1); i < m_entries.size(); i++) { - if (m_entries[i].address == addr && m_entries[i].valid) { - //cout << "m_entries[" << id << ", address " << m_entries[id].address << " is equal to " << addr << endl; - return true; - } - } - return false; -} - -bool PersistentArbiter::lockersExist() { - for (int i = 0; i < m_entries.size(); i++) { - if (m_entries[i].valid == true) { - return true; - } - } - //cout << "no lockers found" << endl; - return false; -} - -void PersistentArbiter::advanceActiveLock() { - assert(lockersExist()); - - //cout << "arbiter advancing lock from " << m_locker; - m_busy = false; - - if (m_locker < (m_entries.size() - 1)) { - for (int i = (m_locker+1); i < m_entries.size(); i++) { - if (m_entries[i].valid == true) { - m_locker = i; - m_busy = true; - //cout << " to " << m_locker << endl; - return; - } - } - } - - if (!m_busy) { - for (int i = 0; i < m_entries.size(); i++) { - if (m_entries[i].valid == true) { - m_locker = i; - m_busy = true; - //cout << " to " << m_locker << endl; - return; - } - } - - assert(m_busy) - } -} - -Address PersistentArbiter::getActiveLockAddress() { - assert( m_entries[m_locker].valid = true ); - return m_entries[m_locker].address; -} - - -NodeID PersistentArbiter::getArbiterId() { - return m_chip_ptr->getID()*RubyConfig::numberOfProcsPerChip(); -} - -bool PersistentArbiter::isBusy() { - return m_busy; -} - -NodeID PersistentArbiter::getActiveLocalId() { - assert( m_entries[m_locker].valid = true ); - return m_entries[m_locker].localId; -} - -void PersistentArbiter::setIssuedAddress(Address addr) { - m_issued_address = addr; -} - -bool PersistentArbiter::isIssuedAddress(Address addr) { - return (m_issued_address == addr); -} - -void PersistentArbiter::print(ostream& out) const { - - out << "["; - for (int i = 0; i < m_entries.size(); i++) { - if (m_entries[i].valid == true) { - out << "( " << m_entries[i].localId << ", " << m_entries[i].address << ") "; - } - } - out << "]" << endl; - -} diff --git a/src/mem/ruby/system/PersistentArbiter.hh b/src/mem/ruby/system/PersistentArbiter.hh deleted file mode 100644 index 1ce05f51f..000000000 --- a/src/mem/ruby/system/PersistentArbiter.hh +++ /dev/null @@ -1,107 +0,0 @@ - -/* - * Copyright (c) 1999-2008 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. - */ - -/* - * PersistentArbiter.hh - * - * Description: - * - * Used for hierarchical distributed persistent request scheme - * - */ - -#ifndef PERSISTENTARBITER_H -#define PERSISTENTARBITER_H - -#include "mem/ruby/common/Global.hh" -#include "mem/gems_common/Vector.hh" -#include "mem/ruby/slicc_interface/AbstractChip.hh" -#include "mem/protocol/AccessPermission.hh" -#include "mem/protocol/AccessType.hh" -#include "mem/ruby/config/RubyConfig.hh" -#include "mem/ruby/common/Address.hh" - -struct ArbiterEntry { - bool valid; - Address address; - AccessType type; - NodeID localId; -}; - -class PersistentArbiter { -public: - - // Constructors - PersistentArbiter(AbstractChip* chip_ptr); - - // Destructor - ~PersistentArbiter(); - - // Public Methods - - void addLocker(NodeID id, Address addr, AccessType type); - void removeLocker(NodeID id); - bool successorRequestPresent(Address addr, NodeID id); - bool lockersExist(); - void advanceActiveLock(); - Address getActiveLockAddress(); - NodeID getArbiterId(); - bool isBusy(); - - void setIssuedAddress(Address addr); - bool isIssuedAddress(Address addr); - - - Address getIssuedAddress() { return m_issued_address; } - - static void printConfig(ostream& out) {} - void print(ostream& out) const; - - NodeID getActiveLocalId(); - -private: - - Address m_issued_address; - AbstractChip* m_chip_ptr; - int m_locker; - bool m_busy; - Vector m_entries; -}; - -// Output operator definition -extern inline -ostream& operator<<(ostream& out, const PersistentArbiter& obj) -{ - obj.print(out); - out << flush; - return out; -} - - -#endif //PERFECTCACHEMEMORY_H diff --git a/src/mem/ruby/system/PersistentTable.cc b/src/mem/ruby/system/PersistentTable.cc deleted file mode 100644 index 7f07251ce..000000000 --- a/src/mem/ruby/system/PersistentTable.cc +++ /dev/null @@ -1,194 +0,0 @@ - -/* - * Copyright (c) 1999-2008 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. - */ - -/* - * $Id$ - * - */ - -#include "mem/ruby/system/PersistentTable.hh" -#include "mem/ruby/common/NetDest.hh" -#include "mem/gems_common/Map.hh" -#include "mem/ruby/common/Address.hh" -#include "mem/ruby/slicc_interface/AbstractChip.hh" -#include "mem/gems_common/util.hh" - -// randomize so that handoffs are not locality-aware -// int persistent_randomize[] = {0, 4, 8, 12, 1, 5, 9, 13, 2, 6, 10, 14, 3, 7, 11, 15}; -// int persistent_randomize[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}; - - -class PersistentTableEntry { -public: - NetDest m_starving; - NetDest m_marked; - NetDest m_request_to_write; -}; - -PersistentTable::PersistentTable(AbstractChip* chip_ptr, int version) -{ - m_chip_ptr = chip_ptr; - m_map_ptr = new Map; - m_version = version; -} - -PersistentTable::~PersistentTable() -{ - delete m_map_ptr; - m_map_ptr = NULL; - m_chip_ptr = NULL; -} - -void PersistentTable::persistentRequestLock(const Address& address, MachineID locker, AccessType type) -{ - - // if (locker == m_chip_ptr->getID() ) - // cout << "Chip " << m_chip_ptr->getID() << ": " << llocker << " requesting lock for " << address << endl; - - // MachineID locker = (MachineID) persistent_randomize[llocker]; - - assert(address == line_address(address)); - if (!m_map_ptr->exist(address)) { - // Allocate if not present - PersistentTableEntry entry; - entry.m_starving.add(locker); - if (type == AccessType_Write) { - entry.m_request_to_write.add(locker); - } - m_map_ptr->add(address, entry); - } else { - PersistentTableEntry& entry = m_map_ptr->lookup(address); - assert(!(entry.m_starving.isElement(locker))); // Make sure we're not already in the locked set - - entry.m_starving.add(locker); - if (type == AccessType_Write) { - entry.m_request_to_write.add(locker); - } - assert(entry.m_marked.isSubset(entry.m_starving)); - } -} - -void PersistentTable::persistentRequestUnlock(const Address& address, MachineID unlocker) -{ - // if (unlocker == m_chip_ptr->getID() ) - // cout << "Chip " << m_chip_ptr->getID() << ": " << uunlocker << " requesting unlock for " << address << endl; - - // MachineID unlocker = (MachineID) persistent_randomize[uunlocker]; - - assert(address == line_address(address)); - assert(m_map_ptr->exist(address)); - PersistentTableEntry& entry = m_map_ptr->lookup(address); - assert(entry.m_starving.isElement(unlocker)); // Make sure we're in the locked set - assert(entry.m_marked.isSubset(entry.m_starving)); - entry.m_starving.remove(unlocker); - entry.m_marked.remove(unlocker); - entry.m_request_to_write.remove(unlocker); - assert(entry.m_marked.isSubset(entry.m_starving)); - - // Deallocate if empty - if (entry.m_starving.isEmpty()) { - assert(entry.m_marked.isEmpty()); - m_map_ptr->erase(address); - } -} - -bool PersistentTable::okToIssueStarving(const Address& address) const -{ - assert(address == line_address(address)); - if (!m_map_ptr->exist(address)) { - return true; // No entry present - } else if (m_map_ptr->lookup(address).m_starving.isElement( (MachineID) {MachineType_L1Cache, m_version})) { - return false; // We can't issue another lockdown until are previous unlock has occurred - } else { - return (m_map_ptr->lookup(address).m_marked.isEmpty()); - } -} - -MachineID PersistentTable::findSmallest(const Address& address) const -{ - assert(address == line_address(address)); - assert(m_map_ptr->exist(address)); - const PersistentTableEntry& entry = m_map_ptr->lookup(address); - // cout << "Node " << m_chip_ptr->getID() << " returning " << persistent_randomize[entry.m_starving.smallestElement()] << " for findSmallest(" << address << ")" << endl; - // return (MachineID) persistent_randomize[entry.m_starving.smallestElement()]; - return (MachineID) { MachineType_L1Cache, entry.m_starving.smallestElement() }; -} - -AccessType PersistentTable::typeOfSmallest(const Address& address) const -{ - assert(address == line_address(address)); - assert(m_map_ptr->exist(address)); - const PersistentTableEntry& entry = m_map_ptr->lookup(address); - if (entry.m_request_to_write.isElement((MachineID) {MachineType_L1Cache, entry.m_starving.smallestElement()})) { - return AccessType_Write; - } else { - return AccessType_Read; - } -} - -void PersistentTable::markEntries(const Address& address) -{ - assert(address == line_address(address)); - if (m_map_ptr->exist(address)) { - PersistentTableEntry& entry = m_map_ptr->lookup(address); - assert(entry.m_marked.isEmpty()); // None should be marked - entry.m_marked = entry.m_starving; // Mark all the nodes currently in the table - } -} - -bool PersistentTable::isLocked(const Address& address) const -{ - assert(address == line_address(address)); - // If an entry is present, it must be locked - return (m_map_ptr->exist(address)); -} - -int PersistentTable::countStarvingForAddress(const Address& address) const -{ - if (m_map_ptr->exist(address)) { - PersistentTableEntry& entry = m_map_ptr->lookup(address); - return (entry.m_starving.count()); - } - else { - return 0; - } -} - -int PersistentTable::countReadStarvingForAddress(const Address& address) const -{ - if (m_map_ptr->exist(address)) { - PersistentTableEntry& entry = m_map_ptr->lookup(address); - return (entry.m_starving.count() - entry.m_request_to_write.count()); - } - else { - return 0; - } -} - - diff --git a/src/mem/ruby/system/PersistentTable.hh b/src/mem/ruby/system/PersistentTable.hh deleted file mode 100644 index 9f2e38fd7..000000000 --- a/src/mem/ruby/system/PersistentTable.hh +++ /dev/null @@ -1,99 +0,0 @@ - -/* - * Copyright (c) 1999-2008 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. - */ - -/* - * $Id$ - * - * Description: - * - */ - -#ifndef PersistentTable_H -#define PersistentTable_H - -#include "mem/ruby/common/Global.hh" -#include "mem/ruby/system/MachineID.hh" -#include "mem/protocol/AccessType.hh" - -class AbstractChip; - -template class Map; -class Address; -class PersistentTableEntry; - -class PersistentTable { -public: - // Constructors - PersistentTable(AbstractChip* chip_ptr, int version); - - // Destructor - ~PersistentTable(); - - // Public Methods - void persistentRequestLock(const Address& address, MachineID locker, AccessType type); - void persistentRequestUnlock(const Address& address, MachineID unlocker); - bool okToIssueStarving(const Address& address) const; - MachineID findSmallest(const Address& address) const; - AccessType typeOfSmallest(const Address& address) const; - void markEntries(const Address& address); - bool isLocked(const Address& addr) const; - int countStarvingForAddress(const Address& addr) const; - int countReadStarvingForAddress(const Address& addr) const; - - static void printConfig(ostream& out) {} - - void print(ostream& out) const; -private: - // Private Methods - - // Private copy constructor and assignment operator - PersistentTable(const PersistentTable& obj); - PersistentTable& operator=(const PersistentTable& obj); - - // Data Members (m_prefix) - Map* m_map_ptr; - AbstractChip* m_chip_ptr; - int m_version; -}; - -// Output operator declaration -ostream& operator<<(ostream& out, const PersistentTable& obj); - -// ******************* Definitions ******************* - -// Output operator definition -extern inline -ostream& operator<<(ostream& out, const PersistentTable& obj) -{ - obj.print(out); - out << flush; - return out; -} - -#endif //PersistentTable_H diff --git a/src/mem/ruby/system/ProcessorInterface.hh b/src/mem/ruby/system/ProcessorInterface.hh new file mode 100644 index 000000000..d76e29f65 --- /dev/null +++ b/src/mem/ruby/system/ProcessorInterface.hh @@ -0,0 +1,45 @@ + +struct ProcessorRequest { + vector cache_requests; +}; + +class ProcessorInterface { + +public: + + void read_atomic(const Address & paddr, void* data, int len) { + assert(paddr.getLineAddress() + RubyConfig::dataBlockBytes() >= paddr + len); + // for now, atomics can't span two blocks. Maybe fix this later + } + + void read(const Address & paddr, const Address & rip, AccessModeType atype, void* data, const int len) { + + // create the CacheRequests + ProcessorRequest* this_request = new ProcessorRequest; + Address split_addr = paddr; + int len_remaining = len; + while (split_addr.getAddress() < paddr.getAddress() + len) { + int split_len = (split_addr.getAddress() + len_remaining <= split_addr.getLineAddress() + RubyConfig::dataBlockBytes()) ? + len_remaining : + RubyConfig::dataBlockBytes() - split_addr.getOffset(); + CacheRequest creq = new CacheRequest( line_address(split_addr), + split_addr, + CacheRequestType_LD, + rip, + atype, + split_len, + PretchBit_No, + laddr, + 0); // SMT thread id); + this_request->cache_requests.push_back(creq); + split_addr += split_len; + len_remaining -= split_len; + } + outstanding_requests.push_back(this_request); + + } + +private: + vector outstanding_requests; + Sequencer* m_sequencer; +}; diff --git a/src/mem/ruby/system/RubyPort.cc b/src/mem/ruby/system/RubyPort.cc new file mode 100644 index 000000000..2a5c5f479 --- /dev/null +++ b/src/mem/ruby/system/RubyPort.cc @@ -0,0 +1,5 @@ + +#include "mem/ruby/system/RubyPort.hh" + +//void (*RubyPort::m_hit_callback)(int64_t) = NULL; +uint16_t RubyPort::m_num_ports = 0; diff --git a/src/mem/ruby/system/RubyPort.hh b/src/mem/ruby/system/RubyPort.hh new file mode 100644 index 000000000..2f391070f --- /dev/null +++ b/src/mem/ruby/system/RubyPort.hh @@ -0,0 +1,60 @@ +#ifndef RUBYPORT_H +#define RUBYPORT_H + +#include "mem/ruby/libruby.hh" +#include +#include + +using namespace std; + +class RubyPort { +public: + RubyPort(const string & name) + : m_name(name) + { + m_port_id = m_num_ports++; + m_request_cnt = 0; + m_hit_callback = NULL; + assert(m_num_ports <= 2048); // see below for reason + } + virtual ~RubyPort() {} + + virtual int64_t makeRequest(const RubyRequest & request) = 0; + + void registerHitCallback(void (*hit_callback)(int64_t request_id)) { + assert(m_hit_callback == NULL); // can't assign hit_callback twice + m_hit_callback = hit_callback; + } + +protected: + const string m_name; + void (*m_hit_callback)(int64_t); + + int64_t makeUniqueRequestID() { + // The request ID is generated by combining the port ID with a request count + // so that request IDs can be formed concurrently by multiple threads. + // IDs are formed as follows: + // + // + // 0 PortID Request Count + // +----+---------------+-----------------------------------------------------+ + // | 63 | 62-48 | 47-0 | + // +----+---------------+-----------------------------------------------------+ + // + // + // This limits the system to a maximum of 2^11 == 2048 components + // and 2^48 ~= 3x10^14 requests per component + + int64_t id = (static_cast(m_port_id) << 48) | m_request_cnt; + m_request_cnt++; + // assert((m_request_cnt & (1<<48)) == 0); + return id; + } + +private: + static uint16_t m_num_ports; + uint16_t m_port_id; + uint64_t m_request_cnt; +}; + +#endif diff --git a/src/mem/ruby/system/Sequencer.cc b/src/mem/ruby/system/Sequencer.cc index 82eef2901..ff5ce1506 100644 --- a/src/mem/ruby/system/Sequencer.cc +++ b/src/mem/ruby/system/Sequencer.cc @@ -27,909 +27,424 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -/* - * $Id: Sequencer.C 1.131 2006/11/06 17:41:01-06:00 bobba@gratiano.cs.wisc.edu $ - * - */ - #include "mem/ruby/common/Global.hh" #include "mem/ruby/system/Sequencer.hh" #include "mem/ruby/system/System.hh" #include "mem/protocol/Protocol.hh" #include "mem/ruby/profiler/Profiler.hh" #include "mem/ruby/system/CacheMemory.hh" -#include "mem/ruby/config/RubyConfig.hh" -//#include "mem/ruby/recorder/Tracer.hh" -#include "mem/ruby/slicc_interface/AbstractChip.hh" -#include "mem/protocol/Chip.hh" -#include "mem/ruby/tester/Tester.hh" +#include "mem/protocol/CacheMsg.hh" +#include "mem/ruby/recorder/Tracer.hh" #include "mem/ruby/common/SubBlock.hh" #include "mem/protocol/Protocol.hh" #include "mem/gems_common/Map.hh" -#include "mem/packet.hh" +#include "mem/ruby/buffers/MessageBuffer.hh" +#include "mem/ruby/slicc_interface/AbstractController.hh" -Sequencer::Sequencer(AbstractChip* chip_ptr, int version) { - m_chip_ptr = chip_ptr; - m_version = version; +//Sequencer::Sequencer(int core_id, MessageBuffer* mandatory_q) +Sequencer::Sequencer(const string & name) + :RubyPort(name) +{ +} + +void Sequencer::init(const vector & argv) +{ m_deadlock_check_scheduled = false; m_outstanding_count = 0; - int smt_threads = RubyConfig::numberofSMTThreads(); - m_writeRequestTable_ptr = new Map*[smt_threads]; - m_readRequestTable_ptr = new Map*[smt_threads]; - - m_packetTable_ptr = new Map; - - for(int p=0; p < smt_threads; ++p){ - m_writeRequestTable_ptr[p] = new Map; - m_readRequestTable_ptr[p] = new Map; + m_max_outstanding_requests = 0; + m_deadlock_threshold = 0; + m_version = -1; + m_instCache_ptr = NULL; + m_dataCache_ptr = NULL; + m_controller = NULL; + for (size_t i=0; igetMandatoryQueue(); + } else if ( argv[i] == "icache") + m_instCache_ptr = RubySystem::getCache(argv[i+1]); + else if ( argv[i] == "dcache") + m_dataCache_ptr = RubySystem::getCache(argv[i+1]); + else if ( argv[i] == "version") + m_version = atoi(argv[i+1].c_str()); + else if ( argv[i] == "max_outstanding_requests") + m_max_outstanding_requests = atoi(argv[i+1].c_str()); + else if ( argv[i] == "deadlock_threshold") + m_deadlock_threshold = atoi(argv[i+1].c_str()); + else { + cerr << "WARNING: Sequencer: Unkown configuration parameter: " << argv[i] << endl; + assert(false); + } } - + assert(m_max_outstanding_requests > 0); + assert(m_deadlock_threshold > 0); + assert(m_version > -1); + assert(m_instCache_ptr != NULL); + assert(m_dataCache_ptr != NULL); + assert(m_controller != NULL); } Sequencer::~Sequencer() { - int smt_threads = RubyConfig::numberofSMTThreads(); - for(int i=0; i < smt_threads; ++i){ - if(m_writeRequestTable_ptr[i]){ - delete m_writeRequestTable_ptr[i]; - } - if(m_readRequestTable_ptr[i]){ - delete m_readRequestTable_ptr[i]; - } - } - if(m_writeRequestTable_ptr){ - delete [] m_writeRequestTable_ptr; - } - if(m_readRequestTable_ptr){ - delete [] m_readRequestTable_ptr; - } + } void Sequencer::wakeup() { // Check for deadlock of any of the requests Time current_time = g_eventQueue_ptr->getTime(); - bool deadlock = false; // Check across all outstanding requests - int smt_threads = RubyConfig::numberofSMTThreads(); int total_outstanding = 0; - for(int p=0; p < smt_threads; ++p){ - Vector
keys = m_readRequestTable_ptr[p]->keys(); - for (int i=0; ilookup(keys[i]); - if (current_time - request.getTime() >= g_DEADLOCK_THRESHOLD) { - WARN_MSG("Possible Deadlock detected"); - WARN_EXPR(request); - WARN_EXPR(m_chip_ptr->getID()); - WARN_EXPR(m_version); - WARN_EXPR(keys.size()); - WARN_EXPR(current_time); - WARN_EXPR(request.getTime()); - WARN_EXPR(current_time - request.getTime()); - WARN_EXPR(*m_readRequestTable_ptr[p]); - ERROR_MSG("Aborting"); - deadlock = true; - } - } - keys = m_writeRequestTable_ptr[p]->keys(); - for (int i=0; ilookup(keys[i]); - if (current_time - request.getTime() >= g_DEADLOCK_THRESHOLD) { - WARN_MSG("Possible Deadlock detected"); - WARN_EXPR(request); - WARN_EXPR(m_chip_ptr->getID()); - WARN_EXPR(m_version); - WARN_EXPR(current_time); - WARN_EXPR(request.getTime()); - WARN_EXPR(current_time - request.getTime()); - WARN_EXPR(keys.size()); - WARN_EXPR(*m_writeRequestTable_ptr[p]); - ERROR_MSG("Aborting"); - deadlock = true; - } - } - total_outstanding += m_writeRequestTable_ptr[p]->size() + m_readRequestTable_ptr[p]->size(); - } // across all request tables + Vector
keys = m_readRequestTable.keys(); + for (int i=0; iissue_time >= m_deadlock_threshold) { + WARN_MSG("Possible Deadlock detected"); + WARN_EXPR(request); + WARN_EXPR(m_version); + WARN_EXPR(keys.size()); + WARN_EXPR(current_time); + WARN_EXPR(request->issue_time); + WARN_EXPR(current_time - request->issue_time); + ERROR_MSG("Aborting"); + } + } + + keys = m_writeRequestTable.keys(); + for (int i=0; iissue_time >= m_deadlock_threshold) { + WARN_MSG("Possible Deadlock detected"); + WARN_EXPR(request); + WARN_EXPR(m_version); + WARN_EXPR(current_time); + WARN_EXPR(request->issue_time); + WARN_EXPR(current_time - request->issue_time); + WARN_EXPR(keys.size()); + ERROR_MSG("Aborting"); + } + } + total_outstanding += m_writeRequestTable.size() + m_readRequestTable.size(); + assert(m_outstanding_count == total_outstanding); if (m_outstanding_count > 0) { // If there are still outstanding requests, keep checking - g_eventQueue_ptr->scheduleEvent(this, g_DEADLOCK_THRESHOLD); + g_eventQueue_ptr->scheduleEvent(this, m_deadlock_threshold); } else { m_deadlock_check_scheduled = false; } } -//returns the total number of requests -int Sequencer::getNumberOutstanding(){ - return m_outstanding_count; -} - -// returns the total number of demand requests -int Sequencer::getNumberOutstandingDemand(){ - int smt_threads = RubyConfig::numberofSMTThreads(); - int total_demand = 0; - for(int p=0; p < smt_threads; ++p){ - Vector
keys = m_readRequestTable_ptr[p]->keys(); - for (int i=0; i< keys.size(); i++) { - CacheMsg& request = m_readRequestTable_ptr[p]->lookup(keys[i]); - if(request.getPrefetch() == PrefetchBit_No){ - total_demand++; - } - } - - keys = m_writeRequestTable_ptr[p]->keys(); - for (int i=0; i< keys.size(); i++) { - CacheMsg& request = m_writeRequestTable_ptr[p]->lookup(keys[i]); - if(request.getPrefetch() == PrefetchBit_No){ - total_demand++; - } - } - } - - return total_demand; -} - -int Sequencer::getNumberOutstandingPrefetch(){ - int smt_threads = RubyConfig::numberofSMTThreads(); - int total_prefetch = 0; - for(int p=0; p < smt_threads; ++p){ - Vector
keys = m_readRequestTable_ptr[p]->keys(); - for (int i=0; i< keys.size(); i++) { - CacheMsg& request = m_readRequestTable_ptr[p]->lookup(keys[i]); - if(request.getPrefetch() == PrefetchBit_Yes){ - total_prefetch++; - } - } - - keys = m_writeRequestTable_ptr[p]->keys(); - for (int i=0; i< keys.size(); i++) { - CacheMsg& request = m_writeRequestTable_ptr[p]->lookup(keys[i]); - if(request.getPrefetch() == PrefetchBit_Yes){ - total_prefetch++; - } - } - } - - return total_prefetch; -} - -bool Sequencer::isPrefetchRequest(const Address & lineaddr){ - int smt_threads = RubyConfig::numberofSMTThreads(); - for(int p=0; p < smt_threads; ++p){ - // check load requests - Vector
keys = m_readRequestTable_ptr[p]->keys(); - for (int i=0; i< keys.size(); i++) { - CacheMsg& request = m_readRequestTable_ptr[p]->lookup(keys[i]); - if(line_address(request.getAddress()) == lineaddr){ - if(request.getPrefetch() == PrefetchBit_Yes){ - return true; - } - else{ - return false; - } - } - } - - // check store requests - keys = m_writeRequestTable_ptr[p]->keys(); - for (int i=0; i< keys.size(); i++) { - CacheMsg& request = m_writeRequestTable_ptr[p]->lookup(keys[i]); - if(line_address(request.getAddress()) == lineaddr){ - if(request.getPrefetch() == PrefetchBit_Yes){ - return true; - } - else{ - return false; - } - } - } - } - // we should've found a matching request - cout << "isRequestPrefetch() ERROR request NOT FOUND : " << lineaddr << endl; - printProgress(cout); - assert(0); -} - -AccessModeType Sequencer::getAccessModeOfRequest(Address addr, int thread){ - if(m_readRequestTable_ptr[thread]->exist(line_address(addr))){ - CacheMsg& request = m_readRequestTable_ptr[thread]->lookup(addr); - return request.getAccessMode(); - } else if(m_writeRequestTable_ptr[thread]->exist(line_address(addr))){ - CacheMsg& request = m_writeRequestTable_ptr[thread]->lookup(addr); - return request.getAccessMode(); - } else { - printProgress(cout); - ERROR_MSG("Request not found in RequestTables"); - } -} - -Address Sequencer::getLogicalAddressOfRequest(Address addr, int thread){ - assert(thread >= 0); - if(m_readRequestTable_ptr[thread]->exist(line_address(addr))){ - CacheMsg& request = m_readRequestTable_ptr[thread]->lookup(addr); - return request.getLogicalAddress(); - } else if(m_writeRequestTable_ptr[thread]->exist(line_address(addr))){ - CacheMsg& request = m_writeRequestTable_ptr[thread]->lookup(addr); - return request.getLogicalAddress(); - } else { - printProgress(cout); - WARN_MSG("Request not found in RequestTables"); - WARN_MSG(addr); - WARN_MSG(thread); - ASSERT(0); - } -} - -// returns the ThreadID of the request -int Sequencer::getRequestThreadID(const Address & addr){ - int smt_threads = RubyConfig::numberofSMTThreads(); - int thread = -1; - int num_found = 0; - for(int p=0; p < smt_threads; ++p){ - if(m_readRequestTable_ptr[p]->exist(addr)){ - num_found++; - thread = p; - } - if(m_writeRequestTable_ptr[p]->exist(addr)){ - num_found++; - thread = p; - } - } - if(num_found != 1){ - cout << "getRequestThreadID ERROR too many matching requests addr = " << addr << endl; - printProgress(cout); - } - ASSERT(num_found == 1); - ASSERT(thread != -1); - - return thread; -} - -// given a line address, return the request's physical address -Address Sequencer::getRequestPhysicalAddress(const Address & lineaddr){ - int smt_threads = RubyConfig::numberofSMTThreads(); - Address physaddr; - int num_found = 0; - for(int p=0; p < smt_threads; ++p){ - if(m_readRequestTable_ptr[p]->exist(lineaddr)){ - num_found++; - physaddr = (m_readRequestTable_ptr[p]->lookup(lineaddr)).getAddress(); - } - if(m_writeRequestTable_ptr[p]->exist(lineaddr)){ - num_found++; - physaddr = (m_writeRequestTable_ptr[p]->lookup(lineaddr)).getAddress(); - } - } - if(num_found != 1){ - cout << "getRequestPhysicalAddress ERROR too many matching requests addr = " << lineaddr << endl; - printProgress(cout); - } - ASSERT(num_found == 1); - - return physaddr; -} - void Sequencer::printProgress(ostream& out) const{ - + /* int total_demand = 0; out << "Sequencer Stats Version " << m_version << endl; out << "Current time = " << g_eventQueue_ptr->getTime() << endl; out << "---------------" << endl; out << "outstanding requests" << endl; - int smt_threads = RubyConfig::numberofSMTThreads(); - for(int p=0; p < smt_threads; ++p){ - Vector
rkeys = m_readRequestTable_ptr[p]->keys(); - int read_size = rkeys.size(); - out << "proc " << m_chip_ptr->getID() << " thread " << p << " Read Requests = " << read_size << endl; - // print the request table - for(int i=0; i < read_size; ++i){ - CacheMsg & request = m_readRequestTable_ptr[p]->lookup(rkeys[i]); - out << "\tRequest[ " << i << " ] = " << request.getType() << " Address " << rkeys[i] << " Posted " << request.getTime() << " PF " << request.getPrefetch() << endl; - if( request.getPrefetch() == PrefetchBit_No ){ - total_demand++; - } - } - - Vector
wkeys = m_writeRequestTable_ptr[p]->keys(); - int write_size = wkeys.size(); - out << "proc " << m_chip_ptr->getID() << " thread " << p << " Write Requests = " << write_size << endl; - // print the request table - for(int i=0; i < write_size; ++i){ - CacheMsg & request = m_writeRequestTable_ptr[p]->lookup(wkeys[i]); + Vector
rkeys = m_readRequestTable.keys(); + int read_size = rkeys.size(); + out << "proc " << m_version << " Read Requests = " << read_size << endl; + // print the request table + for(int i=0; i < read_size; ++i){ + SequencerRequest * request = m_readRequestTable.lookup(rkeys[i]); + out << "\tRequest[ " << i << " ] = " << request->type << " Address " << rkeys[i] << " Posted " << request->issue_time << " PF " << PrefetchBit_No << endl; + total_demand++; + } + + Vector
wkeys = m_writeRequestTable.keys(); + int write_size = wkeys.size(); + out << "proc " << m_version << " Write Requests = " << write_size << endl; + // print the request table + for(int i=0; i < write_size; ++i){ + CacheMsg & request = m_writeRequestTable.lookup(wkeys[i]); out << "\tRequest[ " << i << " ] = " << request.getType() << " Address " << wkeys[i] << " Posted " << request.getTime() << " PF " << request.getPrefetch() << endl; if( request.getPrefetch() == PrefetchBit_No ){ total_demand++; } - } - - out << endl; } + + out << endl; + out << "Total Number Outstanding: " << m_outstanding_count << endl; out << "Total Number Demand : " << total_demand << endl; out << "Total Number Prefetches : " << m_outstanding_count - total_demand << endl; out << endl; out << endl; - + */ } -void Sequencer::printConfig(ostream& out) { - if (TSO) { - out << "sequencer: Sequencer - TSO" << endl; - } else { - out << "sequencer: Sequencer - SC" << endl; - } - out << " max_outstanding_requests: " << g_SEQUENCER_OUTSTANDING_REQUESTS << endl; -} - -bool Sequencer::empty() const { - return m_outstanding_count == 0; +void Sequencer::printConfig(ostream& out) const { + out << "Seqeuncer config: " << m_name << endl; + out << " controller: " << m_controller->getName() << endl; + out << " version: " << m_version << endl; + out << " max_outstanding_requests: " << m_max_outstanding_requests << endl; + out << " deadlock_threshold: " << m_deadlock_threshold << endl; } // Insert the request on the correct request table. Return true if // the entry was already present. -bool Sequencer::insertRequest(const CacheMsg& request) { - int thread = request.getThreadID(); - assert(thread >= 0); - int total_outstanding = 0; - int smt_threads = RubyConfig::numberofSMTThreads(); - for(int p=0; p < smt_threads; ++p){ - total_outstanding += m_writeRequestTable_ptr[p]->size() + m_readRequestTable_ptr[p]->size(); - } +bool Sequencer::insertRequest(SequencerRequest* request) { + int total_outstanding = m_writeRequestTable.size() + m_readRequestTable.size(); + assert(m_outstanding_count == total_outstanding); // See if we should schedule a deadlock check if (m_deadlock_check_scheduled == false) { - g_eventQueue_ptr->scheduleEvent(this, g_DEADLOCK_THRESHOLD); + g_eventQueue_ptr->scheduleEvent(this, m_deadlock_threshold); m_deadlock_check_scheduled = true; } - if ((request.getType() == CacheRequestType_ST) || - (request.getType() == CacheRequestType_ATOMIC)) { - if (m_writeRequestTable_ptr[thread]->exist(line_address(request.getAddress()))) { - m_writeRequestTable_ptr[thread]->lookup(line_address(request.getAddress())) = request; - return true; + Address line_addr(request->ruby_request.paddr); + line_addr.makeLineAddress(); + if ((request->ruby_request.type == RubyRequestType_ST) || + (request->ruby_request.type == RubyRequestType_RMW)) { + if (m_writeRequestTable.exist(line_addr)) { + m_writeRequestTable.lookup(line_addr) = request; + // return true; + assert(0); // drh5: isn't this an error? do you lose the initial request? } - m_writeRequestTable_ptr[thread]->allocate(line_address(request.getAddress())); - m_writeRequestTable_ptr[thread]->lookup(line_address(request.getAddress())) = request; + m_writeRequestTable.allocate(line_addr); + m_writeRequestTable.lookup(line_addr) = request; m_outstanding_count++; } else { - if (m_readRequestTable_ptr[thread]->exist(line_address(request.getAddress()))) { - m_readRequestTable_ptr[thread]->lookup(line_address(request.getAddress())) = request; - return true; + if (m_readRequestTable.exist(line_addr)) { + m_readRequestTable.lookup(line_addr) = request; + // return true; + assert(0); // drh5: isn't this an error? do you lose the initial request? } - m_readRequestTable_ptr[thread]->allocate(line_address(request.getAddress())); - m_readRequestTable_ptr[thread]->lookup(line_address(request.getAddress())) = request; + m_readRequestTable.allocate(line_addr); + m_readRequestTable.lookup(line_addr) = request; m_outstanding_count++; } g_system_ptr->getProfiler()->sequencerRequests(m_outstanding_count); - total_outstanding = 0; - for(int p=0; p < smt_threads; ++p){ - total_outstanding += m_writeRequestTable_ptr[p]->size() + m_readRequestTable_ptr[p]->size(); - } - + total_outstanding = m_writeRequestTable.size() + m_readRequestTable.size(); assert(m_outstanding_count == total_outstanding); + return false; } -void Sequencer::removeRequest(const CacheMsg& request) { - int thread = request.getThreadID(); - assert(thread >= 0); - int total_outstanding = 0; - int smt_threads = RubyConfig::numberofSMTThreads(); - for(int p=0; p < smt_threads; ++p){ - total_outstanding += m_writeRequestTable_ptr[p]->size() + m_readRequestTable_ptr[p]->size(); - } - assert(m_outstanding_count == total_outstanding); +void Sequencer::removeRequest(SequencerRequest* srequest) { + + assert(m_outstanding_count == m_writeRequestTable.size() + m_readRequestTable.size()); - if ((request.getType() == CacheRequestType_ST) || - (request.getType() == CacheRequestType_ATOMIC)) { - m_writeRequestTable_ptr[thread]->deallocate(line_address(request.getAddress())); + const RubyRequest & ruby_request = srequest->ruby_request; + Address line_addr(ruby_request.paddr); + line_addr.makeLineAddress(); + if ((ruby_request.type == RubyRequestType_ST) || + (ruby_request.type == RubyRequestType_RMW)) { + m_writeRequestTable.deallocate(line_addr); } else { - m_readRequestTable_ptr[thread]->deallocate(line_address(request.getAddress())); + m_readRequestTable.deallocate(line_addr); } m_outstanding_count--; - total_outstanding = 0; - for(int p=0; p < smt_threads; ++p){ - total_outstanding += m_writeRequestTable_ptr[p]->size() + m_readRequestTable_ptr[p]->size(); - } - assert(m_outstanding_count == total_outstanding); -} - -void Sequencer::writeCallback(const Address& address) { - DataBlock data; - writeCallback(address, data); + assert(m_outstanding_count == m_writeRequestTable.size() + m_readRequestTable.size()); } void Sequencer::writeCallback(const Address& address, DataBlock& data) { - // process oldest thread first - int thread = -1; - Time oldest_time = 0; - int smt_threads = RubyConfig::numberofSMTThreads(); - for(int t=0; t < smt_threads; ++t){ - if(m_writeRequestTable_ptr[t]->exist(address)){ - CacheMsg & request = m_writeRequestTable_ptr[t]->lookup(address); - if(thread == -1 || (request.getTime() < oldest_time) ){ - thread = t; - oldest_time = request.getTime(); - } - } - } - // make sure we found an oldest thread - ASSERT(thread != -1); - - CacheMsg & request = m_writeRequestTable_ptr[thread]->lookup(address); - - writeCallback(address, data, GenericMachineType_NULL, PrefetchBit_No, thread); -} - -void Sequencer::writeCallback(const Address& address, DataBlock& data, GenericMachineType respondingMach, PrefetchBit pf, int thread) { assert(address == line_address(address)); - assert(thread >= 0); - assert(m_writeRequestTable_ptr[thread]->exist(line_address(address))); + assert(m_writeRequestTable.exist(line_address(address))); - writeCallback(address, data, respondingMach, thread); - -} - -void Sequencer::writeCallback(const Address& address, DataBlock& data, GenericMachineType respondingMach, int thread) { - assert(address == line_address(address)); - assert(m_writeRequestTable_ptr[thread]->exist(line_address(address))); - CacheMsg request = m_writeRequestTable_ptr[thread]->lookup(address); - assert( request.getThreadID() == thread); + SequencerRequest* request = m_writeRequestTable.lookup(address); removeRequest(request); - assert((request.getType() == CacheRequestType_ST) || - (request.getType() == CacheRequestType_ATOMIC)); - - hitCallback(request, data, respondingMach, thread); + assert((request->ruby_request.type == RubyRequestType_ST) || + (request->ruby_request.type == RubyRequestType_RMW)); -} - -void Sequencer::readCallback(const Address& address) { - DataBlock data; - readCallback(address, data); + hitCallback(request, data); } void Sequencer::readCallback(const Address& address, DataBlock& data) { - // process oldest thread first - int thread = -1; - Time oldest_time = 0; - int smt_threads = RubyConfig::numberofSMTThreads(); - for(int t=0; t < smt_threads; ++t){ - if(m_readRequestTable_ptr[t]->exist(address)){ - CacheMsg & request = m_readRequestTable_ptr[t]->lookup(address); - if(thread == -1 || (request.getTime() < oldest_time) ){ - thread = t; - oldest_time = request.getTime(); - } - } - } - // make sure we found an oldest thread - ASSERT(thread != -1); - - CacheMsg & request = m_readRequestTable_ptr[thread]->lookup(address); - - readCallback(address, data, GenericMachineType_NULL, PrefetchBit_No, thread); -} - -void Sequencer::readCallback(const Address& address, DataBlock& data, GenericMachineType respondingMach, PrefetchBit pf, int thread) { assert(address == line_address(address)); - assert(m_readRequestTable_ptr[thread]->exist(line_address(address))); + assert(m_readRequestTable.exist(line_address(address))); - readCallback(address, data, respondingMach, thread); -} - -void Sequencer::readCallback(const Address& address, DataBlock& data, GenericMachineType respondingMach, int thread) { - assert(address == line_address(address)); - assert(m_readRequestTable_ptr[thread]->exist(line_address(address))); - - CacheMsg request = m_readRequestTable_ptr[thread]->lookup(address); - assert( request.getThreadID() == thread ); + SequencerRequest* request = m_readRequestTable.lookup(address); removeRequest(request); - assert((request.getType() == CacheRequestType_LD) || - (request.getType() == CacheRequestType_IFETCH) - ); + assert((request->ruby_request.type == RubyRequestType_LD) || + (request->ruby_request.type == RubyRequestType_IFETCH)); - hitCallback(request, data, respondingMach, thread); + hitCallback(request, data); } -void Sequencer::hitCallback(const CacheMsg& request, DataBlock& data, GenericMachineType respondingMach, int thread) { - int size = request.getSize(); - Address request_address = request.getAddress(); - Address request_logical_address = request.getLogicalAddress(); - Address request_line_address = line_address(request_address); - CacheRequestType type = request.getType(); - int threadID = request.getThreadID(); - Time issued_time = request.getTime(); - int logical_proc_no = ((m_chip_ptr->getID() * RubyConfig::numberOfProcsPerChip()) + m_version) * RubyConfig::numberofSMTThreads() + threadID; - - DEBUG_MSG(SEQUENCER_COMP, MedPrio, size); +void Sequencer::hitCallback(SequencerRequest* srequest, DataBlock& data) { + const RubyRequest & ruby_request = srequest->ruby_request; + int size = ruby_request.len; + Address request_address(ruby_request.paddr); + Address request_line_address(ruby_request.paddr); + request_line_address.makeLineAddress(); + RubyRequestType type = ruby_request.type; + Time issued_time = srequest->issue_time; // Set this cache entry to the most recently used - if (type == CacheRequestType_IFETCH) { - if (Protocol::m_TwoLevelCache) { - if (m_chip_ptr->m_L1Cache_L1IcacheMemory_vec[m_version]->isTagPresent(request_line_address)) { - m_chip_ptr->m_L1Cache_L1IcacheMemory_vec[m_version]->setMRU(request_line_address); - } - } - else { - if (m_chip_ptr->m_L1Cache_cacheMemory_vec[m_version]->isTagPresent(request_line_address)) { - m_chip_ptr->m_L1Cache_cacheMemory_vec[m_version]->setMRU(request_line_address); - } - } + if (type == RubyRequestType_IFETCH) { + if (m_instCache_ptr->isTagPresent(request_line_address) ) + m_instCache_ptr->setMRU(request_line_address); } else { - if (Protocol::m_TwoLevelCache) { - if (m_chip_ptr->m_L1Cache_L1DcacheMemory_vec[m_version]->isTagPresent(request_line_address)) { - m_chip_ptr->m_L1Cache_L1DcacheMemory_vec[m_version]->setMRU(request_line_address); - } - } - else { - if (m_chip_ptr->m_L1Cache_cacheMemory_vec[m_version]->isTagPresent(request_line_address)) { - m_chip_ptr->m_L1Cache_cacheMemory_vec[m_version]->setMRU(request_line_address); - } - } + if (m_dataCache_ptr->isTagPresent(request_line_address) ) + m_dataCache_ptr->setMRU(request_line_address); } assert(g_eventQueue_ptr->getTime() >= issued_time); Time miss_latency = g_eventQueue_ptr->getTime() - issued_time; - if (PROTOCOL_DEBUG_TRACE) { - g_system_ptr->getProfiler()->profileTransition("Seq", (m_chip_ptr->getID()*RubyConfig::numberOfProcsPerChip()+m_version), -1, request.getAddress(), "", "Done", "", - int_to_string(miss_latency)+" cycles "+GenericMachineType_to_string(respondingMach)+" "+CacheRequestType_to_string(request.getType())+" "+PrefetchBit_to_string(request.getPrefetch())); - } - - DEBUG_MSG(SEQUENCER_COMP, MedPrio, request_address); - DEBUG_MSG(SEQUENCER_COMP, MedPrio, request.getPrefetch()); - if (request.getPrefetch() == PrefetchBit_Yes) { - DEBUG_MSG(SEQUENCER_COMP, MedPrio, "return"); - g_system_ptr->getProfiler()->swPrefetchLatency(miss_latency, type, respondingMach); - return; // Ignore the software prefetch, don't callback the driver - } - // Profile the miss latency for all non-zero demand misses if (miss_latency != 0) { - g_system_ptr->getProfiler()->missLatency(miss_latency, type, respondingMach); - - } - - bool write = - (type == CacheRequestType_ST) || - (type == CacheRequestType_ATOMIC); + g_system_ptr->getProfiler()->missLatency(miss_latency, type); - if (TSO && write) { - m_chip_ptr->m_L1Cache_storeBuffer_vec[m_version]->callBack(line_address(request.getAddress()), data, - m_packetTable_ptr->lookup(request.getAddress())); - } else { - - // Copy the correct bytes out of the cache line into the subblock - SubBlock subblock(request_address, request_logical_address, size); - subblock.mergeFrom(data); // copy the correct bytes from DataBlock in the SubBlock - - // Scan the store buffer to see if there are any outstanding stores we need to collect - if (TSO) { - m_chip_ptr->m_L1Cache_storeBuffer_vec[m_version]->updateSubBlock(subblock); + if (Debug::getProtocolTrace()) { + g_system_ptr->getProfiler()->profileTransition("Seq", m_version, Address(ruby_request.paddr), + "", "Done", "", int_to_string(miss_latency)+" cycles"); } + } + /* + if (request.getPrefetch() == PrefetchBit_Yes) { + return; // Ignore the prefetch + } + */ - // Call into the Driver and let it read and/or modify the sub-block - Packet* pkt = m_packetTable_ptr->lookup(request.getAddress()); - - // update data if this is a store/atomic - - /* - if (pkt->req->isCondSwap()) { - L1Cache_Entry entry = m_L1Cache_vec[m_version]->lookup(Address(pkt->req->physAddr())); - DataBlk datablk = entry->getDataBlk(); - uint8_t *orig_data = datablk.getArray(); - if ( datablk.equal(pkt->req->getExtraData()) ) - datablk->setArray(pkt->getData()); - pkt->setData(orig_data); - } - */ - - g_system_ptr->getDriver()->hitCallback(pkt); - m_packetTable_ptr->remove(request.getAddress()); - - // If the request was a Store or Atomic, apply the changes in the SubBlock to the DataBlock - // (This is only triggered for the non-TSO case) - if (write) { - assert(!TSO); - subblock.mergeTo(data); // copy the correct bytes from SubBlock into the DataBlock + // update the data + if (ruby_request.data != NULL) { + if ((type == RubyRequestType_LD) || + (type == RubyRequestType_IFETCH)) { + memcpy(ruby_request.data, data.getData(request_address.getOffset(), ruby_request.len), ruby_request.len); + } else { + data.setData(ruby_request.data, request_address.getOffset(), ruby_request.len); } } -} -void Sequencer::printDebug(){ - //notify driver of debug - g_system_ptr->getDriver()->printDebug(); + m_hit_callback(srequest->id); + delete srequest; } -//dsm: breaks build, delayed // Returns true if the sequencer already has a load or store outstanding -bool -Sequencer::isReady(const Packet* pkt) const -{ - - int cpu_number = pkt->req->contextId(); - la_t logical_addr = pkt->req->getVaddr(); - pa_t physical_addr = pkt->req->getPaddr(); - CacheRequestType type_of_request; - if ( pkt->req->isInstFetch() ) { - type_of_request = CacheRequestType_IFETCH; - } else if ( pkt->req->isLocked() || pkt->req->isSwap() ) { - type_of_request = CacheRequestType_ATOMIC; - } else if ( pkt->isRead() ) { - type_of_request = CacheRequestType_LD; - } else if ( pkt->isWrite() ) { - type_of_request = CacheRequestType_ST; - } else { - assert(false); +bool Sequencer::isReady(const RubyRequest& request) const { + // POLINA: check if we are currently flushing the write buffer, if so Ruby is returned as not ready + // to simulate stalling of the front-end + // Do we stall all the sequencers? If it is atomic instruction - yes! + if (m_outstanding_count >= m_max_outstanding_requests) { + return false; } - int thread = pkt->req->threadId(); - - CacheMsg request(Address( physical_addr ), - Address( physical_addr ), - type_of_request, - Address(0), - AccessModeType_UserMode, // User/supervisor mode - 0, // Size in bytes of request - PrefetchBit_No, // Not a prefetch - 0, // Version number - Address(logical_addr), // Virtual Address - thread // SMT thread - ); - return isReady(request); -} -bool -Sequencer::isReady(const CacheMsg& request) const -{ - if (m_outstanding_count >= g_SEQUENCER_OUTSTANDING_REQUESTS) { - //cout << "TOO MANY OUTSTANDING: " << m_outstanding_count << " " << g_SEQUENCER_OUTSTANDING_REQUESTS << " VER " << m_version << endl; + if( m_writeRequestTable.exist(line_address(Address(request.paddr))) || + m_readRequestTable.exist(line_address(Address(request.paddr))) ){ + //cout << "OUTSTANDING REQUEST EXISTS " << p << " VER " << m_version << endl; //printProgress(cout); return false; } - // This code allows reads to be performed even when we have a write - // request outstanding for the line - bool write = - (request.getType() == CacheRequestType_ST) || - (request.getType() == CacheRequestType_ATOMIC); - - // LUKE - disallow more than one request type per address - // INVARIANT: at most one request type per address, per processor - int smt_threads = RubyConfig::numberofSMTThreads(); - for(int p=0; p < smt_threads; ++p){ - if( m_writeRequestTable_ptr[p]->exist(line_address(request.getAddress())) || - m_readRequestTable_ptr[p]->exist(line_address(request.getAddress())) ){ - //cout << "OUTSTANDING REQUEST EXISTS " << p << " VER " << m_version << endl; - //printProgress(cout); - return false; - } - } - - if (TSO) { - return m_chip_ptr->m_L1Cache_storeBuffer_vec[m_version]->isReady(); - } return true; } -//dsm: breaks build, delayed -// Called by Driver (Simics or Tester). -void -Sequencer::makeRequest(Packet* pkt) -{ - int cpu_number = pkt->req->contextId(); - la_t logical_addr = pkt->req->getVaddr(); - pa_t physical_addr = pkt->req->getPaddr(); - int request_size = pkt->getSize(); - CacheRequestType type_of_request; - PrefetchBit prefetch; - bool write = false; - if ( pkt->req->isInstFetch() ) { - type_of_request = CacheRequestType_IFETCH; - } else if ( pkt->req->isLocked() || pkt->req->isSwap() ) { - type_of_request = CacheRequestType_ATOMIC; - write = true; - } else if ( pkt->isRead() ) { - type_of_request = CacheRequestType_LD; - } else if ( pkt->isWrite() ) { - type_of_request = CacheRequestType_ST; - write = true; - } else { - assert(false); - } - if (pkt->req->isPrefetch()) { - prefetch = PrefetchBit_Yes; - } else { - prefetch = PrefetchBit_No; - } - la_t virtual_pc = pkt->req->getPC(); - int isPriv = false; // TODO: get permission data - int thread = pkt->req->threadId(); - - AccessModeType access_mode = AccessModeType_UserMode; // TODO: get actual permission - - CacheMsg request(Address( physical_addr ), - Address( physical_addr ), - type_of_request, - Address(virtual_pc), - access_mode, // User/supervisor mode - request_size, // Size in bytes of request - prefetch, - 0, // Version number - Address(logical_addr), // Virtual Address - thread // SMT thread - ); - - if ( TSO && write && !pkt->req->isPrefetch() ) { - assert(m_chip_ptr->m_L1Cache_storeBuffer_vec[m_version]->isReady()); - m_chip_ptr->m_L1Cache_storeBuffer_vec[m_version]->insertStore(pkt, request); - return; - } - - m_packetTable_ptr->insert(Address( physical_addr ), pkt); - - doRequest(request); -} - -bool Sequencer::doRequest(const CacheMsg& request) { - bool hit = false; - // Check the fast path - DataBlock* data_ptr; - - int thread = request.getThreadID(); - - hit = tryCacheAccess(line_address(request.getAddress()), - request.getType(), - request.getProgramCounter(), - request.getAccessMode(), - request.getSize(), - data_ptr); - - if (hit && (request.getType() == CacheRequestType_IFETCH || !REMOVE_SINGLE_CYCLE_DCACHE_FAST_PATH) ) { - DEBUG_MSG(SEQUENCER_COMP, MedPrio, "Fast path hit"); - hitCallback(request, *data_ptr, GenericMachineType_L1Cache, thread); - return true; - } - - if (TSO && (request.getType() == CacheRequestType_LD || request.getType() == CacheRequestType_IFETCH)) { - - // See if we can satisfy the load entirely from the store buffer - SubBlock subblock(line_address(request.getAddress()), request.getSize()); - if (m_chip_ptr->m_L1Cache_storeBuffer_vec[m_version]->trySubBlock(subblock)) { - DataBlock dummy; - hitCallback(request, dummy, GenericMachineType_NULL, thread); // Call with an 'empty' datablock, since the data is in the store buffer - return true; - } - } - - DEBUG_MSG(SEQUENCER_COMP, MedPrio, "Fast path miss"); - issueRequest(request); - return hit; +bool Sequencer::empty() const { + return (m_writeRequestTable.size() == 0) && (m_readRequestTable.size() == 0); } -void Sequencer::issueRequest(const CacheMsg& request) { - bool found = insertRequest(request); - - if (!found) { - CacheMsg msg = request; - msg.getAddress() = line_address(request.getAddress()); // Make line address - - // Fast Path L1 misses are profiled here - all non-fast path misses are profiled within the generated protocol code - if (!REMOVE_SINGLE_CYCLE_DCACHE_FAST_PATH) { - g_system_ptr->getProfiler()->addPrimaryStatSample(msg, m_chip_ptr->getID()); - } - - if (PROTOCOL_DEBUG_TRACE) { - g_system_ptr->getProfiler()->profileTransition("Seq", (m_chip_ptr->getID()*RubyConfig::numberOfProcsPerChip() + m_version), -1, msg.getAddress(),"", "Begin", "", CacheRequestType_to_string(request.getType())); - } - -#if 0 - // Commented out by nate binkert because I removed the trace stuff - if (g_system_ptr->getTracer()->traceEnabled()) { - g_system_ptr->getTracer()->traceRequest((m_chip_ptr->getID()*RubyConfig::numberOfProcsPerChip()+m_version), msg.getAddress(), msg.getProgramCounter(), - msg.getType(), g_eventQueue_ptr->getTime()); - } -#endif - - Time latency = 0; // initialzed to an null value - - latency = SEQUENCER_TO_CONTROLLER_LATENCY; - - // Send the message to the cache controller - assert(latency > 0); - m_chip_ptr->m_L1Cache_mandatoryQueue_vec[m_version]->enqueue(msg, latency); - - } // !found +int64_t Sequencer::makeRequest(const RubyRequest & request) +{ + assert(Address(request.paddr).getOffset() + request.len <= RubySystem::getBlockSizeBytes()); + if (isReady(request)) { + int64_t id = makeUniqueRequestID(); + SequencerRequest *srequest = new SequencerRequest(request, id, g_eventQueue_ptr->getTime()); + bool found = insertRequest(srequest); + if (!found) + issueRequest(request); + + // TODO: issue hardware prefetches here + return id; + } + else { + return -1; + } +} + +void Sequencer::issueRequest(const RubyRequest& request) { + + // TODO: get rid of CacheMsg, CacheRequestType, and AccessModeTYpe, & have SLICC use RubyRequest and subtypes natively + CacheRequestType ctype; + switch(request.type) { + case RubyRequestType_IFETCH: + ctype = CacheRequestType_IFETCH; + break; + case RubyRequestType_LD: + ctype = CacheRequestType_LD; + break; + case RubyRequestType_ST: + ctype = CacheRequestType_ST; + break; + case RubyRequestType_RMW: + ctype = CacheRequestType_ATOMIC; + break; + default: + assert(0); + } + AccessModeType amtype; + switch(request.access_mode){ + case RubyAccessMode_User: + amtype = AccessModeType_UserMode; + break; + case RubyAccessMode_Supervisor: + amtype = AccessModeType_SupervisorMode; + break; + case RubyAccessMode_Device: + amtype = AccessModeType_UserMode; + break; + default: + assert(0); + } + Address line_addr(request.paddr); + line_addr.makeLineAddress(); + CacheMsg msg(line_addr, Address(request.paddr), ctype, Address(request.pc), amtype, request.len, PrefetchBit_No); + + if (Debug::getProtocolTrace()) { + g_system_ptr->getProfiler()->profileTransition("Seq", m_version, Address(request.paddr), + "", "Begin", "", RubyRequestType_to_string(request.type)); + } + + if (g_system_ptr->getTracer()->traceEnabled()) { + g_system_ptr->getTracer()->traceRequest(m_name, line_addr, Address(request.pc), + request.type, g_eventQueue_ptr->getTime()); + } + + Time latency = 0; // initialzed to an null value + + if (request.type == RubyRequestType_IFETCH) + latency = m_instCache_ptr->getLatency(); + else + latency = m_dataCache_ptr->getLatency(); + + // Send the message to the cache controller + assert(latency > 0); + + + m_mandatory_q_ptr->enqueue(msg, latency); } - +/* bool Sequencer::tryCacheAccess(const Address& addr, CacheRequestType type, - const Address& pc, AccessModeType access_mode, + AccessModeType access_mode, int size, DataBlock*& data_ptr) { if (type == CacheRequestType_IFETCH) { - if (Protocol::m_TwoLevelCache) { - return m_chip_ptr->m_L1Cache_L1IcacheMemory_vec[m_version]->tryCacheAccess(line_address(addr), type, data_ptr); - } - else { - return m_chip_ptr->m_L1Cache_cacheMemory_vec[m_version]->tryCacheAccess(line_address(addr), type, data_ptr); - } + return m_instCache_ptr->tryCacheAccess(line_address(addr), type, data_ptr); } else { - if (Protocol::m_TwoLevelCache) { - return m_chip_ptr->m_L1Cache_L1DcacheMemory_vec[m_version]->tryCacheAccess(line_address(addr), type, data_ptr); - } - else { - return m_chip_ptr->m_L1Cache_cacheMemory_vec[m_version]->tryCacheAccess(line_address(addr), type, data_ptr); - } - } -} - -void Sequencer::resetRequestTime(const Address& addr, int thread){ - assert(thread >= 0); - //reset both load and store requests, if they exist - if(m_readRequestTable_ptr[thread]->exist(line_address(addr))){ - CacheMsg& request = m_readRequestTable_ptr[thread]->lookup(addr); - if( request.m_AccessMode != AccessModeType_UserMode){ - cout << "resetRequestType ERROR read request addr = " << addr << " thread = "<< thread << " is SUPERVISOR MODE" << endl; - printProgress(cout); - } - //ASSERT(request.m_AccessMode == AccessModeType_UserMode); - request.setTime(g_eventQueue_ptr->getTime()); + return m_dataCache_ptr->tryCacheAccess(line_address(addr), type, data_ptr); } - if(m_writeRequestTable_ptr[thread]->exist(line_address(addr))){ - CacheMsg& request = m_writeRequestTable_ptr[thread]->lookup(addr); - if( request.m_AccessMode != AccessModeType_UserMode){ - cout << "resetRequestType ERROR write request addr = " << addr << " thread = "<< thread << " is SUPERVISOR MODE" << endl; - printProgress(cout); - } - //ASSERT(request.m_AccessMode == AccessModeType_UserMode); - request.setTime(g_eventQueue_ptr->getTime()); - } -} - -// removes load request from queue -void Sequencer::removeLoadRequest(const Address & addr, int thread){ - removeRequest(getReadRequest(addr, thread)); -} - -void Sequencer::removeStoreRequest(const Address & addr, int thread){ - removeRequest(getWriteRequest(addr, thread)); -} - -// returns the read CacheMsg -CacheMsg & Sequencer::getReadRequest( const Address & addr, int thread ){ - Address temp = addr; - assert(thread >= 0); - assert(temp == line_address(temp)); - assert(m_readRequestTable_ptr[thread]->exist(addr)); - return m_readRequestTable_ptr[thread]->lookup(addr); -} - -CacheMsg & Sequencer::getWriteRequest( const Address & addr, int thread){ - Address temp = addr; - assert(thread >= 0); - assert(temp == line_address(temp)); - assert(m_writeRequestTable_ptr[thread]->exist(addr)); - return m_writeRequestTable_ptr[thread]->lookup(addr); } +*/ void Sequencer::print(ostream& out) const { - out << "[Sequencer: " << m_chip_ptr->getID() + out << "[Sequencer: " << m_version << ", outstanding requests: " << m_outstanding_count; - int smt_threads = RubyConfig::numberofSMTThreads(); - for(int p=0; p < smt_threads; ++p){ - out << ", read request table[ " << p << " ]: " << *m_readRequestTable_ptr[p] - << ", write request table[ " << p << " ]: " << *m_writeRequestTable_ptr[p]; - } + out << ", read request table: " << m_readRequestTable + << ", write request table: " << m_writeRequestTable; out << "]"; } @@ -941,20 +456,183 @@ void Sequencer::checkCoherence(const Address& addr) { #endif } +/* bool Sequencer::getRubyMemoryValue(const Address& addr, char* value, - unsigned int size_in_bytes ) { - for(unsigned int i=0; i < size_in_bytes; i++) { - std::cerr << __FILE__ << "(" << __LINE__ << "): Not implemented. " << std::endl; - value[i] = 0; // _read_physical_memory( m_chip_ptr->getID()*RubyConfig::numberOfProcsPerChip()+m_version, - // addr.getAddress() + i, 1 ); - } - return false; // Do nothing? + unsigned int size_in_bytes ) +{ + bool found = false; + const Address lineAddr = line_address(addr); + DataBlock data; + PhysAddress paddr(addr); + DataBlock* dataPtr = &data; + + MachineID l2_mach = map_L2ChipId_to_L2Cache(addr, m_chip_ptr->getID() ); + int l2_ver = l2_mach.num%RubyConfig::numberOfL2CachePerChip(); + + if (Protocol::m_TwoLevelCache) { + if(Protocol::m_CMP){ + assert(n->m_L2Cache_L2cacheMemory_vec[l2_ver] != NULL); + } + else{ + assert(n->m_L1Cache_cacheMemory_vec[m_version] != NULL); + } + } + + if (n->m_L1Cache_L1IcacheMemory_vec[m_version]->tryCacheAccess(lineAddr, CacheRequestType_IFETCH, dataPtr)){ + n->m_L1Cache_L1IcacheMemory_vec[m_version]->getMemoryValue(addr, value, size_in_bytes); + found = true; + } else if (n->m_L1Cache_L1DcacheMemory_vec[m_version]->tryCacheAccess(lineAddr, CacheRequestType_LD, dataPtr)){ + n->m_L1Cache_L1DcacheMemory_vec[m_version]->getMemoryValue(addr, value, size_in_bytes); + found = true; + } else if (Protocol::m_CMP && n->m_L2Cache_L2cacheMemory_vec[l2_ver]->tryCacheAccess(lineAddr, CacheRequestType_LD, dataPtr)){ + n->m_L2Cache_L2cacheMemory_vec[l2_ver]->getMemoryValue(addr, value, size_in_bytes); + found = true; + // } else if (n->TBE_TABLE_MEMBER_VARIABLE->isPresent(lineAddr)){ +// ASSERT(n->TBE_TABLE_MEMBER_VARIABLE->isPresent(lineAddr)); +// L1Cache_TBE tbeEntry = n->TBE_TABLE_MEMBER_VARIABLE->lookup(lineAddr); + +// int offset = addr.getOffset(); +// for(int i=0; igetID() << " NOT IN CACHE, Value at Directory is: " << (int) value[0] << endl; + n = dynamic_cast(g_system_ptr->getChip(map_Address_to_DirectoryNode(addr)/RubyConfig::numberOfDirectoryPerChip())); + int dir_version = map_Address_to_DirectoryNode(addr)%RubyConfig::numberOfDirectoryPerChip(); + for(unsigned int i=0; im_Directory_directory_vec[dir_version]->lookup(lineAddr).m_DataBlk.getByte(offset + i); + } + // Address not found + //WARN_MSG("Couldn't find address"); + //WARN_EXPR(addr); + found = false; + } + return true; } bool Sequencer::setRubyMemoryValue(const Address& addr, char *value, unsigned int size_in_bytes) { char test_buffer[64]; - return false; // Do nothing? + // idea here is that coherent cache should find the + // latest data, the update it + bool found = false; + const Address lineAddr = line_address(addr); + PhysAddress paddr(addr); + DataBlock data; + DataBlock* dataPtr = &data; + Chip* n = dynamic_cast(m_chip_ptr); + + MachineID l2_mach = map_L2ChipId_to_L2Cache(addr, m_chip_ptr->getID() ); + int l2_ver = l2_mach.num%RubyConfig::numberOfL2CachePerChip(); + + assert(n->m_L1Cache_L1IcacheMemory_vec[m_version] != NULL); + assert(n->m_L1Cache_L1DcacheMemory_vec[m_version] != NULL); + if (Protocol::m_TwoLevelCache) { + if(Protocol::m_CMP){ + assert(n->m_L2Cache_L2cacheMemory_vec[l2_ver] != NULL); + } + else{ + assert(n->m_L1Cache_cacheMemory_vec[m_version] != NULL); + } + } + + if (n->m_L1Cache_L1IcacheMemory_vec[m_version]->tryCacheAccess(lineAddr, CacheRequestType_IFETCH, dataPtr)){ + n->m_L1Cache_L1IcacheMemory_vec[m_version]->setMemoryValue(addr, value, size_in_bytes); + found = true; + } else if (n->m_L1Cache_L1DcacheMemory_vec[m_version]->tryCacheAccess(lineAddr, CacheRequestType_LD, dataPtr)){ + n->m_L1Cache_L1DcacheMemory_vec[m_version]->setMemoryValue(addr, value, size_in_bytes); + found = true; + } else if (Protocol::m_CMP && n->m_L2Cache_L2cacheMemory_vec[l2_ver]->tryCacheAccess(lineAddr, CacheRequestType_LD, dataPtr)){ + n->m_L2Cache_L2cacheMemory_vec[l2_ver]->setMemoryValue(addr, value, size_in_bytes); + found = true; + } else { + // Address not found + n = dynamic_cast(g_system_ptr->getChip(map_Address_to_DirectoryNode(addr)/RubyConfig::numberOfDirectoryPerChip())); + int dir_version = map_Address_to_DirectoryNode(addr)%RubyConfig::numberOfDirectoryPerChip(); + for(unsigned int i=0; im_Directory_directory_vec[dir_version]->lookup(lineAddr).m_DataBlk.setByte(offset + i, value[i]); + } + found = false; + } + + if (found){ + found = getRubyMemoryValue(addr, test_buffer, size_in_bytes); + assert(found); + if(value[0] != test_buffer[0]){ + WARN_EXPR((int) value[0]); + WARN_EXPR((int) test_buffer[0]); + ERROR_MSG("setRubyMemoryValue failed to set value."); + } + } + + return true; +} +*/ +/* + +void +Sequencer::rubyMemAccess(const uint64 paddr, char* data, const int len, const AccessType type) +{ + if ( type == AccessType_Read || type == AccessType_Write ) { + // need to break up the packet data + uint64 guest_ptr = paddr; + Vector datablocks; + while (paddr + len != guest_ptr) { + Address addr(guest_ptr); + Address line_addr = line_address(addr); + + int bytes_copied; + if (addr.getOffset() == 0) { + bytes_copied = (guest_ptr + RubyConfig::dataBlockBytes() > paddr + len)? + (paddr + len - guest_ptr): + RubyConfig::dataBlockBytes(); + } else { + bytes_copied = RubyConfig::dataBlockBytes() - addr.getOffset(); + if (guest_ptr + bytes_copied > paddr + len) + bytes_copied = paddr + len - guest_ptr; + } + + // first we need to find all data blocks that have to be updated for a write + // and the highest block for a read + for(int i=0;im_L1Cache_L1IcacheMemory_vec[i]->isTagPresent(line_address(addr))) + datablocks.insertAtBottom(&m_chip_ptr->m_L1Cache_L1IcacheMemory_vec[i]->lookup(line_addr).getDataBlk()); + if(m_chip_ptr->m_L1Cache_L1DcacheMemory_vec[i]->isTagPresent(line_address(addr))) + datablocks.insertAtBottom(&m_chip_ptr->m_L1Cache_L1DcacheMemory_vec[i]->lookup(line_addr).getDataBlk()); + } else { + if(m_chip_ptr->m_L1Cache_cacheMemory_vec[i]->isTagPresent(line_address(addr))) + datablocks.insertAtBottom(&m_chip_ptr->m_L1Cache_cacheMemory_vec[i]->lookup(line_addr).getDataBlk()); + } + } + if (Protocol::m_TwoLevelCache){ + int l2_bank = map_L2ChipId_to_L2Cache(addr, 0).num; // TODO: ONLY WORKS WITH CMP!!! + if (m_chip_ptr->m_L2Cache_L2cacheMemory_vec[l2_bank]->isTagPresent(line_address(Address(paddr)))) { + datablocks.insertAtBottom(&m_chip_ptr->m_L2Cache_L2cacheMemory_vec[l2_bank]->lookup(addr).getDataBlk()); + } + } + assert(dynamic_cast(m_chip_ptr)->m_Directory_directory_vec.size() > map_Address_to_DirectoryNode(addr)); + DirectoryMemory* dir = dynamic_cast(m_chip_ptr)->m_Directory_directory_vec[map_Address_to_DirectoryNode(addr)]; + Directory_Entry& entry = dir->lookup(line_addr); + datablocks.insertAtBottom(&entry.getDataBlk()); + + if (pkt->isRead()){ + datablocks[0]->copyData(pkt_data, addr.getOffset(), bytes_copied); + } else {// pkt->isWrite() { + for (int i=0;isetData(pkt_data, addr.getOffset(), bytes_copied); + } + + guest_ptr += bytes_copied; + pkt_data += bytes_copied; + datablocks.clear(); + } } +*/ diff --git a/src/mem/ruby/system/Sequencer.hh b/src/mem/ruby/system/Sequencer.hh index 1ccfd97ce..254f5a092 100644 --- a/src/mem/ruby/system/Sequencer.hh +++ b/src/mem/ruby/system/Sequencer.hh @@ -44,19 +44,31 @@ #include "mem/protocol/AccessModeType.hh" #include "mem/protocol/GenericMachineType.hh" #include "mem/protocol/PrefetchBit.hh" +#include "mem/ruby/system/RubyPort.hh" #include "mem/gems_common/Map.hh" +#include "mem/ruby/common/Address.hh" class DataBlock; -class AbstractChip; class CacheMsg; -class Address; class MachineID; -class Packet; +class CacheMemory; +class AbstractController; -class Sequencer : public Consumer { +struct SequencerRequest { + RubyRequest ruby_request; + int64_t id; + Time issue_time; + + SequencerRequest(const RubyRequest & _ruby_request, int64_t _id, Time _issue_time) + : ruby_request(_ruby_request), id(_id), issue_time(_issue_time) + {} +}; + +class Sequencer : public Consumer, public RubyPort { public: // Constructors - Sequencer(AbstractChip* chip_ptr, int version); + Sequencer(const string & name); + void init(const vector & argv); // Destructor ~Sequencer(); @@ -64,87 +76,53 @@ public: // Public Methods void wakeup(); // Used only for deadlock detection - static void printConfig(ostream& out); - - // returns total number of outstanding request (includes prefetches) - int getNumberOutstanding(); - // return only total number of outstanding demand requests - int getNumberOutstandingDemand(); - // return only total number of outstanding prefetch requests - int getNumberOutstandingPrefetch(); - - // remove load/store request from queue - void removeLoadRequest(const Address & addr, int thread); - void removeStoreRequest(const Address & addr, int thread); + void printConfig(ostream& out) const; void printProgress(ostream& out) const; - // returns a pointer to the request in the request tables - CacheMsg & getReadRequest( const Address & addr, int thread ); - CacheMsg & getWriteRequest( const Address & addr, int thread ); - void writeCallback(const Address& address, DataBlock& data); void readCallback(const Address& address, DataBlock& data); - void writeCallback(const Address& address); - void readCallback(const Address& address); - void writeCallback(const Address& address, DataBlock& data, GenericMachineType respondingMach, PrefetchBit pf, int thread); - void readCallback(const Address& address, DataBlock& data, GenericMachineType respondingMach, PrefetchBit pf, int thread); - void writeCallback(const Address& address, DataBlock& data, GenericMachineType respondingMach, int thread); - void readCallback(const Address& address, DataBlock& data, GenericMachineType respondingMach, int thread); - - // returns the thread ID of the request - int getRequestThreadID(const Address & addr); - // returns the physical address of the request - Address getRequestPhysicalAddress(const Address & lineaddr); - // returns whether a request is a prefetch request - bool isPrefetchRequest(const Address & lineaddr); - - //notifies driver of debug print - void printDebug(); // called by Tester or Simics - void makeRequest(Packet* pkt); - bool doRequest(const CacheMsg& request); - void issueRequest(const CacheMsg& request); - bool isReady(const Packet* pkt) const; - bool isReady(const CacheMsg& request) const; // depricate this function + int64_t makeRequest(const RubyRequest & request); + bool isReady(const RubyRequest& request) const; bool empty() const; - void resetRequestTime(const Address& addr, int thread); - Address getLogicalAddressOfRequest(Address address, int thread); - AccessModeType getAccessModeOfRequest(Address address, int thread); - //uint64 getSequenceNumberOfRequest(Address addr, int thread); void print(ostream& out) const; void checkCoherence(const Address& address); - bool getRubyMemoryValue(const Address& addr, char* value, unsigned int size_in_bytes); - bool setRubyMemoryValue(const Address& addr, char *value, unsigned int size_in_bytes); + // bool getRubyMemoryValue(const Address& addr, char* value, unsigned int size_in_bytes); + // bool setRubyMemoryValue(const Address& addr, char *value, unsigned int size_in_bytes); - void removeRequest(const CacheMsg& request); + void removeRequest(SequencerRequest* request); private: // Private Methods bool tryCacheAccess(const Address& addr, CacheRequestType type, const Address& pc, AccessModeType access_mode, int size, DataBlock*& data_ptr); - // void conflictCallback(const CacheMsg& request, GenericMachineType respondingMach, int thread); - void hitCallback(const CacheMsg& request, DataBlock& data, GenericMachineType respondingMach, int thread); - bool insertRequest(const CacheMsg& request); + void issueRequest(const RubyRequest& request); + + void hitCallback(SequencerRequest* request, DataBlock& data); + bool insertRequest(SequencerRequest* request); // Private copy constructor and assignment operator Sequencer(const Sequencer& obj); Sequencer& operator=(const Sequencer& obj); - // Data Members (m_ prefix) - AbstractChip* m_chip_ptr; +private: + int m_max_outstanding_requests; + int m_deadlock_threshold; + + AbstractController* m_controller; + MessageBuffer* m_mandatory_q_ptr; + CacheMemory* m_dataCache_ptr; + CacheMemory* m_instCache_ptr; // indicates what processor on the chip this sequencer is associated with int m_version; + int m_controller_type; - // One request table per SMT thread - Map** m_writeRequestTable_ptr; - Map** m_readRequestTable_ptr; - - Map* m_packetTable_ptr; - + Map m_writeRequestTable; + Map m_readRequestTable; // Global outstanding request count, across all request tables int m_outstanding_count; bool m_deadlock_check_scheduled; diff --git a/src/mem/ruby/system/StoreBuffer.cc b/src/mem/ruby/system/StoreBuffer.cc deleted file mode 100644 index 280decdd8..000000000 --- a/src/mem/ruby/system/StoreBuffer.cc +++ /dev/null @@ -1,302 +0,0 @@ - -/* - * Copyright (c) 1999-2008 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. - */ - -/* - * $Id$ - * - */ - -#include "mem/ruby/common/Global.hh" -#include "mem/ruby/config/RubyConfig.hh" -#include "mem/ruby/system/StoreBuffer.hh" -#include "mem/ruby/slicc_interface/AbstractChip.hh" -#include "mem/ruby/system/System.hh" -#include "mem/ruby/common/Driver.hh" -#include "mem/gems_common/Vector.hh" -#include "mem/ruby/eventqueue/RubyEventQueue.hh" -#include "mem/ruby/profiler/AddressProfiler.hh" -#include "mem/ruby/system/Sequencer.hh" -#include "mem/ruby/common/SubBlock.hh" -#include "mem/ruby/profiler/Profiler.hh" -#include "mem/packet.hh" - -// *** Begin Helper class *** -struct StoreBufferEntry { - StoreBufferEntry() {} // So we can allocate a vector of StoreBufferEntries - StoreBufferEntry(const SubBlock& block, CacheRequestType type, const Address& pc, AccessModeType access_mode, int size, int thread) : m_subblock(block) { - m_type = type; - m_pc = pc; - m_access_mode = access_mode; - m_size = size; - m_thread = thread; - m_time = g_eventQueue_ptr->getTime(); - } - - void print(ostream& out) const - { - out << "[StoreBufferEntry: " - << "SubBlock: " << m_subblock - << ", Type: " << m_type - << ", PC: " << m_pc - << ", AccessMode: " << m_access_mode - << ", Size: " << m_size - << ", Thread: " << m_thread - << ", Time: " << m_time - << "]"; - } - - SubBlock m_subblock; - CacheRequestType m_type; - Address m_pc; - AccessModeType m_access_mode; - int m_size; - int m_thread; - Time m_time; -}; - -extern inline -ostream& operator<<(ostream& out, const StoreBufferEntry& obj) -{ - obj.print(out); - out << flush; - return out; -} - -// *** End Helper class *** - -const int MAX_ENTRIES = 128; - -static void inc_index(int& index) -{ - index++; - if (index >= MAX_ENTRIES) { - index = 0; - } -} - -StoreBuffer::StoreBuffer(AbstractChip* chip_ptr, int version) : - m_store_cache() -{ - m_chip_ptr = chip_ptr; - m_version = version; - m_queue_ptr = new Vector(MAX_ENTRIES); - m_queue_ptr->setSize(MAX_ENTRIES); - m_pending = false; - m_seen_atomic = false; - m_head = 0; - m_tail = 0; - m_size = 0; - m_deadlock_check_scheduled = false; -} - -StoreBuffer::~StoreBuffer() -{ - delete m_queue_ptr; -} - -// Used only to check for deadlock -void StoreBuffer::wakeup() -{ - // Check for deadlock of any of the requests - Time current_time = g_eventQueue_ptr->getTime(); - - int queue_pointer = m_head; - for (int i=0; i= g_DEADLOCK_THRESHOLD) { - WARN_EXPR(getEntry(queue_pointer)); - WARN_EXPR(m_chip_ptr->getID()); - WARN_EXPR(current_time); - ERROR_MSG("Possible Deadlock detected"); - } - inc_index(queue_pointer); - } - - if (m_size > 0) { // If there are still outstanding requests, keep checking - g_eventQueue_ptr->scheduleEvent(this, g_DEADLOCK_THRESHOLD); - } else { - m_deadlock_check_scheduled = false; - } -} - -void StoreBuffer::printConfig(ostream& out) -{ - out << "Store buffer entries: " << MAX_ENTRIES << " (Only valid if TSO is enabled)" << endl; -} - -// Handle an incoming store request, this method is responsible for -// calling hitCallback as needed -void -StoreBuffer::insertStore(Packet* pkt, const CacheMsg& request) -{ - Address addr = request.getAddress(); - CacheRequestType type = request.getType(); - Address pc = request.getProgramCounter(); - AccessModeType access_mode = request.getAccessMode(); - int size = request.getSize(); - int threadID = request.getThreadID(); - - DEBUG_MSG(STOREBUFFER_COMP, MedPrio, "insertStore"); - DEBUG_EXPR(STOREBUFFER_COMP, MedPrio, g_eventQueue_ptr->getTime()); - assert((type == CacheRequestType_ST) || (type == CacheRequestType_ATOMIC)); - assert(isReady()); - - // See if we should schedule a deadlock check - if (m_deadlock_check_scheduled == false) { - g_eventQueue_ptr->scheduleEvent(this, g_DEADLOCK_THRESHOLD); - m_deadlock_check_scheduled = true; - } - - // Perform the hit-callback for the store - SubBlock subblock(addr, size); - if(type == CacheRequestType_ST) { - g_system_ptr->getDriver()->hitCallback(pkt); - assert(subblock.getSize() != 0); - } else { - // wait to perform the hitCallback until later for Atomics - } - - // Perform possible pre-fetch - if(!isEmpty()) { - Packet new_pkt(pkt); - pkt->req->setFlags(Request::PREFETCH); - m_chip_ptr->getSequencer(m_version)->makeRequest(&new_pkt); - } - - // Update the StoreCache - m_store_cache.add(subblock); - - // Enqueue the entry - StoreBufferEntry entry(subblock, type, pc, access_mode, size, threadID); // FIXME - enqueue(entry); - - if(type == CacheRequestType_ATOMIC) { - m_seen_atomic = true; - } - - processHeadOfQueue(); -} - -void StoreBuffer::callBack(const Address& addr, DataBlock& data, Packet* pkt) -{ - DEBUG_MSG(STOREBUFFER_COMP, MedPrio, "callBack"); - DEBUG_EXPR(STOREBUFFER_COMP, MedPrio, g_eventQueue_ptr->getTime()); - assert(!isEmpty()); - assert(m_pending == true); - assert(line_address(addr) == addr); - assert(line_address(m_pending_address) == addr); - assert(line_address(peek().m_subblock.getAddress()) == addr); - CacheRequestType type = peek().m_type; - //int threadID = peek().m_thread; - assert((type == CacheRequestType_ST) || (type == CacheRequestType_ATOMIC)); - m_pending = false; - - // If oldest entry was ATOMIC, perform the callback - if(type == CacheRequestType_ST) { - // We already performed the call back for the store at insert time - } else { - // We waited to perform the hitCallback until now for Atomics - peek().m_subblock.mergeFrom(data); // copy the correct bytes from DataBlock into the SubBlock for the Load part of the atomic Load/Store - g_system_ptr->getDriver()->hitCallback(pkt); - m_seen_atomic = false; - - /// FIXME - record the time spent in the store buffer - split out ST vs ATOMIC - } - assert(peek().m_subblock.getSize() != 0); - - // Apply the head entry to the datablock - peek().m_subblock.mergeTo(data); // For both the Store and Atomic cases - - // Update the StoreCache - m_store_cache.remove(peek().m_subblock); - - // Dequeue the entry from the store buffer - dequeue(); - - if (isEmpty()) { - assert(m_store_cache.isEmpty()); - } - - if(type == CacheRequestType_ATOMIC) { - assert(isEmpty()); - } - - // See if we can remove any more entries - processHeadOfQueue(); -} - -void StoreBuffer::processHeadOfQueue() -{ - if(!isEmpty() && !m_pending) { - StoreBufferEntry& entry = peek(); - assert(m_pending == false); - m_pending = true; - m_pending_address = entry.m_subblock.getAddress(); - CacheMsg request(entry.m_subblock.getAddress(), entry.m_subblock.getAddress(), entry.m_type, entry.m_pc, entry.m_access_mode, entry.m_size, PrefetchBit_No, 0, Address(0), entry.m_thread); - m_chip_ptr->getSequencer(m_version)->doRequest(request); - } -} - -bool StoreBuffer::isReady() const -{ - return ((m_size < MAX_ENTRIES) && (!m_seen_atomic)); -} - -// Queue implementation methods - -StoreBufferEntry& StoreBuffer::peek() -{ - return getEntry(m_head); -} - -void StoreBuffer::dequeue() -{ - assert(m_size > 0); - m_size--; - inc_index(m_head); -} - -void StoreBuffer::enqueue(const StoreBufferEntry& entry) -{ - // assert(isReady()); - (*m_queue_ptr)[m_tail] = entry; - m_size++; - g_system_ptr->getProfiler()->storeBuffer(m_size, m_store_cache.size()); - inc_index(m_tail); -} - -StoreBufferEntry& StoreBuffer::getEntry(int index) -{ - return (*m_queue_ptr)[index]; -} - -void StoreBuffer::print(ostream& out) const -{ - out << "[StoreBuffer]"; -} - diff --git a/src/mem/ruby/system/StoreBuffer.hh b/src/mem/ruby/system/StoreBuffer.hh deleted file mode 100644 index 2c9283f4b..000000000 --- a/src/mem/ruby/system/StoreBuffer.hh +++ /dev/null @@ -1,121 +0,0 @@ - -/* - * Copyright (c) 1999-2008 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. - */ - -/* - * $Id$ - * - * Description: - * - */ - -#ifndef StoreBuffer_H -#define StoreBuffer_H - -#include "mem/ruby/common/Global.hh" -#include "mem/ruby/common/Consumer.hh" -#include "mem/ruby/common/Address.hh" -#include "mem/protocol/AccessModeType.hh" -#include "mem/protocol/CacheRequestType.hh" -#include "mem/ruby/system/StoreCache.hh" - -class CacheMsg; -class DataBlock; -class SubBlock; -class StoreBufferEntry; -class AbstractChip; -class Packet; - -template class Vector; - -class StoreBuffer : public Consumer { -public: - // Constructors - StoreBuffer(AbstractChip* chip_ptr, int version); - - // Destructor - ~StoreBuffer(); - - // Public Methods - void wakeup(); // Used only for deadlock detection - void callBack(const Address& addr, DataBlock& data, Packet* pkt); - void insertStore(Packet* pkt, const CacheMsg& request); - void updateSubBlock(SubBlock& sub_block) const { m_store_cache.update(sub_block); } - bool trySubBlock(const SubBlock& sub_block) const { assert(isReady()); return m_store_cache.check(sub_block); } - void print(ostream& out) const; - bool isEmpty() const { return (m_size == 0); } - bool isReady() const; - - // Class methods - static void printConfig(ostream& out); - -private: - // Private Methods - void processHeadOfQueue(); - - StoreBufferEntry& peek(); - void dequeue(); - void enqueue(const StoreBufferEntry& entry); - StoreBufferEntry& getEntry(int index); - - // Private copy constructor and assignment operator - StoreBuffer(const StoreBuffer& obj); - StoreBuffer& operator=(const StoreBuffer& obj); - - // Data Members (m_ prefix) - int m_version; - - Vector* m_queue_ptr; - int m_head; - int m_tail; - int m_size; - - StoreCache m_store_cache; - - AbstractChip* m_chip_ptr; - bool m_pending; - Address m_pending_address; - bool m_seen_atomic; - bool m_deadlock_check_scheduled; -}; - -// Output operator declaration -ostream& operator<<(ostream& out, const StoreBuffer& obj); - -// ******************* Definitions ******************* - -// Output operator definition -extern inline -ostream& operator<<(ostream& out, const StoreBuffer& obj) -{ - obj.print(out); - out << flush; - return out; -} - -#endif //StoreBuffer_H diff --git a/src/mem/ruby/system/StoreCache.cc b/src/mem/ruby/system/StoreCache.cc deleted file mode 100644 index a11b2ac50..000000000 --- a/src/mem/ruby/system/StoreCache.cc +++ /dev/null @@ -1,178 +0,0 @@ - -/* - * Copyright (c) 1999-2008 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. - */ - -/* - * $Id$ - * - */ - -#include "mem/ruby/system/StoreCache.hh" -#include "mem/ruby/system/System.hh" -#include "mem/ruby/common/Driver.hh" -#include "mem/gems_common/Vector.hh" -#include "mem/ruby/common/DataBlock.hh" -#include "mem/ruby/common/SubBlock.hh" -#include "mem/gems_common/Map.hh" - -// Helper class -struct StoreCacheEntry { - StoreCacheEntry() { - m_byte_counters.setSize(RubyConfig::dataBlockBytes()); - for(int i=0; i m_byte_counters; - int m_line_counter; -}; - -StoreCache::StoreCache() -{ - m_internal_cache_ptr = new Map; -} - -StoreCache::~StoreCache() -{ - delete m_internal_cache_ptr; -} - -bool StoreCache::isEmpty() const -{ - return m_internal_cache_ptr->size() == 0; -} - -int StoreCache::size() const { return m_internal_cache_ptr->size(); } - -void StoreCache::add(const SubBlock& block) -{ - if (m_internal_cache_ptr->exist(line_address(block.getAddress())) == false) { - m_internal_cache_ptr->allocate(line_address(block.getAddress())); - } - - StoreCacheEntry& entry = m_internal_cache_ptr->lookup(line_address(block.getAddress())); - - // For each byte in entry change the bytes and inc. the counters - int starting_offset = block.getAddress().getOffset(); - int size = block.getSize(); - for (int index=0; index < size; index++) { - // Update counter - entry.m_byte_counters[starting_offset+index]++; - - // Record data - entry.m_datablock.setByte(starting_offset+index, block.getByte(index)); - - DEBUG_EXPR(SEQUENCER_COMP, LowPrio, block.getAddress()); - DEBUG_EXPR(SEQUENCER_COMP, LowPrio, int(block.getByte(index))); - DEBUG_EXPR(SEQUENCER_COMP, LowPrio, starting_offset+index); - } - - // Increment the counter - entry.m_line_counter++; -} - -void StoreCache::remove(const SubBlock& block) -{ - assert(m_internal_cache_ptr->exist(line_address(block.getAddress()))); - - StoreCacheEntry& entry = m_internal_cache_ptr->lookup(line_address(block.getAddress())); - - // Decrement the byte counters - int starting_offset = block.getAddress().getOffset(); - int size = block.getSize(); - for (int index=0; index < size; index++) { - // Update counter - entry.m_byte_counters[starting_offset+index]--; - } - - // Decrement the line counter - entry.m_line_counter--; - assert(entry.m_line_counter >= 0); - - // Check to see if we should de-allocate this entry - if (entry.m_line_counter == 0) { - m_internal_cache_ptr->deallocate(line_address(block.getAddress())); - } -} - -bool StoreCache::check(const SubBlock& block) const -{ - if (m_internal_cache_ptr->exist(line_address(block.getAddress())) == false) { - return false; - } else { - // Lookup the entry - StoreCacheEntry& entry = m_internal_cache_ptr->lookup(line_address(block.getAddress())); - - // See if all the bytes are valid - int starting_offset = block.getAddress().getOffset(); - int size = block.getSize(); - for (int index=0; index < size; index++) { - if (entry.m_byte_counters[starting_offset+index] > 0) { - // So far so good - } else { - // not all the bytes were valid - return false; - } - } - } - return true; -} - -void StoreCache::update(SubBlock& block) const -{ - if (m_internal_cache_ptr->exist(line_address(block.getAddress()))) { - // Lookup the entry - StoreCacheEntry& entry = m_internal_cache_ptr->lookup(line_address(block.getAddress())); - - // Copy all appropriate and valid bytes from the store cache to - // the SubBlock - int starting_offset = block.getAddress().getOffset(); - int size = block.getSize(); - for (int index=0; index < size; index++) { - - DEBUG_EXPR(SEQUENCER_COMP, LowPrio, block.getAddress()); - DEBUG_EXPR(SEQUENCER_COMP, LowPrio, int(entry.m_datablock.getByte(starting_offset+index))); - DEBUG_EXPR(SEQUENCER_COMP, LowPrio, starting_offset+index); - - // If this byte is valid, copy the data into the sub-block - if (entry.m_byte_counters[starting_offset+index] > 0) { - block.setByte(index, entry.m_datablock.getByte(starting_offset+index)); - } - } - } -} - -void StoreCache::print(ostream& out) const -{ - out << "[StoreCache]"; -} - diff --git a/src/mem/ruby/system/StoreCache.hh b/src/mem/ruby/system/StoreCache.hh deleted file mode 100644 index 81eecde38..000000000 --- a/src/mem/ruby/system/StoreCache.hh +++ /dev/null @@ -1,85 +0,0 @@ - -/* - * Copyright (c) 1999-2008 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. - */ - -/* - * $Id$ - * - * Description: - * - */ - -#ifndef StoreCache_H -#define StoreCache_H - -#include "mem/ruby/common/Global.hh" -#include "mem/ruby/common/Address.hh" - - -class DataBlock; -class SubBlock; -class StoreCacheEntry; - -template class Map; - -class StoreCache { -public: - // Constructors - StoreCache(); - - // Destructor - ~StoreCache(); - - // Public Methods - void add(const SubBlock& block); - void remove(const SubBlock& block); - bool check(const SubBlock& block) const; - void update(SubBlock& block) const; - bool isEmpty() const; - int size() const; - void print(ostream& out) const; - -private: - Map* m_internal_cache_ptr; -}; - -// Output operator declaration -ostream& operator<<(ostream& out, const StoreCache& obj); - -// ******************* Definitions ******************* - -// Output operator definition -extern inline -ostream& operator<<(ostream& out, const StoreCache& obj) -{ - obj.print(out); - out << flush; - return out; -} - -#endif //StoreCache_H diff --git a/src/mem/ruby/system/System.cc b/src/mem/ruby/system/System.cc index 0e1a29130..9d1119f01 100644 --- a/src/mem/ruby/system/System.cc +++ b/src/mem/ruby/system/System.cc @@ -38,134 +38,306 @@ #include "mem/ruby/system/System.hh" +#include "mem/ruby/common/Address.hh" #include "mem/ruby/profiler/Profiler.hh" #include "mem/ruby/network/Network.hh" -#include "mem/ruby/tester/Tester.hh" -#include "mem/ruby/tester/SyntheticDriver.hh" -#include "mem/ruby/tester/DeterministicDriver.hh" -#include "mem/protocol/Chip.hh" -//#include "mem/ruby/recorder/Tracer.hh" +#include "mem/ruby/recorder/Tracer.hh" #include "mem/protocol/Protocol.hh" - -RubySystem::RubySystem() +#include "mem/ruby/buffers/MessageBuffer.hh" +#include "mem/ruby/system/Sequencer.hh" +#include "mem/ruby/system/DMASequencer.hh" +#include "mem/ruby/system/MemoryVector.hh" +#include "mem/protocol/ControllerFactory.hh" +#include "mem/ruby/slicc_interface/AbstractController.hh" +#include "mem/ruby/system/CacheMemory.hh" +#include "mem/ruby/system/DirectoryMemory.hh" +#include "mem/ruby/network/simple/Topology.hh" +#include "mem/ruby/network/simple/SimpleNetwork.hh" +#include "mem/ruby/system/RubyPort.hh" +#include "mem/ruby/network/garnet-flexible-pipeline/GarnetNetwork.hh" +#include "mem/ruby/network/garnet-fixed-pipeline/GarnetNetwork_d.hh" +#include "mem/ruby/system/MemoryControl.hh" + +int RubySystem::m_random_seed; +bool RubySystem::m_randomization; +int RubySystem::m_tech_nm; +int RubySystem::m_freq_mhz; +int RubySystem::m_block_size_bytes; +int RubySystem::m_block_size_bits; +uint64 RubySystem::m_memory_size_bytes; +int RubySystem::m_memory_size_bits; + +map< string, RubyPort* > RubySystem::m_ports; +map< string, CacheMemory* > RubySystem::m_caches; +map< string, DirectoryMemory* > RubySystem::m_directories; +map< string, Sequencer* > RubySystem::m_sequencers; +map< string, DMASequencer* > RubySystem::m_dma_sequencers; +map< string, AbstractController* > RubySystem::m_controllers; +map< string, MemoryControl* > RubySystem::m_memorycontrols; + + +Network* RubySystem::m_network_ptr; +map< string, Topology*> RubySystem::m_topologies; +Profiler* RubySystem::m_profiler_ptr; +Tracer* RubySystem::m_tracer_ptr; + +MemoryVector* RubySystem::m_mem_vec_ptr; + + +RubySystem* RubySystem::create(const vector & sys_conf) { - init(); - m_preinitialized_driver = false; - createDriver(); - - /* gem5:Binkert for decomissiong of tracer - m_tracer_ptr = new Tracer; - */ - - /* gem5:Arka for decomissiong of log_tm - if (XACT_MEMORY) { - m_xact_isolation_checker = new XactIsolationChecker; - m_xact_commit_arbiter = new XactCommitArbiter; - m_xact_visualizer = new XactVisualizer; - } -*/ + if (g_system_ptr == NULL) + return new RubySystem(sys_conf); + return g_system_ptr; } -RubySystem::RubySystem(Driver* _driver) +void RubySystem::init(const vector & argv) { - init(); - m_preinitialized_driver = true; - m_driver_ptr = _driver; -} + for (size_t i=0; i < argv.size(); i+=2) { + if (argv[i] == "random_seed") { + m_random_seed = atoi(argv[i+1].c_str()); + srandom(m_random_seed); + } else if (argv[i] == "randomization") { + m_randomization = string_to_bool(argv[i+1]); + } else if (argv[i] == "tech_nm") { + m_tech_nm = atoi(argv[i+1].c_str()); + } else if (argv[i] == "freq_mhz") { + m_freq_mhz = atoi(argv[i+1].c_str()); + } else if (argv[i] == "block_size_bytes") { + m_block_size_bytes = atoi(argv[i+1].c_str()); + assert(is_power_of_2(m_block_size_bytes)); + m_block_size_bits = log_int(m_block_size_bytes); + } else if (argv[i] == "debug") { + + } else if (argv[i] == "tracer") { + + } else if (argv[i] == "profiler") { + + // } else if (argv[i] == "MI_example") { -RubySystem::~RubySystem() -{ - for (int i = 0; i < m_chip_vector.size(); i++) { - delete m_chip_vector[i]; + } else { + cerr << "Error: Unknown RubySystem config parameter -- " << argv[i] << endl; + assert(0); + } } - if (!m_preinitialized_driver) - delete m_driver_ptr; - delete m_network_ptr; - delete m_profiler_ptr; - /* gem5:Binkert for decomissiong of tracer - delete m_tracer_ptr; - */ } -void RubySystem::init() +RubySystem::RubySystem(const vector & sys_conf) { - DEBUG_MSG(SYSTEM_COMP, MedPrio,"initializing"); - - m_driver_ptr = NULL; - m_profiler_ptr = new Profiler; + // DEBUG_MSG(SYSTEM_COMP, MedPrio,"initializing"); + + for (size_t i=0;i & argv = sys_conf[i].argv; + if (type == "RubySystem") { + init(argv); // initialize system-wide variables before doing anything else! + } else if (type == "Debug") { + g_debug_ptr = new Debug(name, argv); + } + } - // NETWORK INITIALIZATION - // create the network by calling a function that calls new - m_network_ptr = Network::createNetwork(RubyConfig::numberOfChips()); + assert( g_debug_ptr != NULL); + g_eventQueue_ptr = new RubyEventQueue; + g_system_ptr = this; + m_mem_vec_ptr = new MemoryVector; + + /* object contruction is broken into two steps (Constructor and init) to avoid cyclic dependencies + * e.g. a sequencer needs a pointer to a controller and a controller needs a pointer to a sequencer + */ + + vector memory_control_names; + + for (size_t i=0;i & argv = sys_conf[i].argv; + if (type == "RubySystem" || type == "Debug") + continue; + else if (type == "SetAssociativeCache") + m_caches[name] = new CacheMemory(name); + else if (type == "DirectoryMemory") + m_directories[name] = new DirectoryMemory(name); + else if (type == "Sequencer") { + m_sequencers[name] = new Sequencer(name); + m_ports[name] = m_sequencers[name]; + } else if (type == "DMASequencer") { + m_dma_sequencers[name] = new DMASequencer(name); + m_ports[name] = m_dma_sequencers[name]; + } else if (type == "Topology") { + assert(m_topologies.size() == 0); // only one toplogy at a time is supported right now + m_topologies[name] = new Topology(name); + } else if (type == "SimpleNetwork") { + assert(m_network_ptr == NULL); // only one network at a time is supported right now + m_network_ptr = new SimpleNetwork(name); + } else if (type.find("generated") == 0) { + string controller_type = type.substr(10); + m_controllers[name] = ControllerFactory::createController(controller_type, name); +// printf ("ss: generated %s \n", controller_type); +//added by SS + } else if (type == "Tracer") { + //m_tracers[name] = new Tracer(name); + m_tracer_ptr = new Tracer(name); + } else if (type == "Profiler") { + m_profiler_ptr = new Profiler(name); + } else if (type == "GarnetNetwork") { + assert(m_network_ptr == NULL); // only one network at a time is supported right now + m_network_ptr = new GarnetNetwork(name); + } else if (type == "GarnetNetwork_d") { + assert(m_network_ptr == NULL); // only one network at a time is supported right now + m_network_ptr = new GarnetNetwork_d(name); + } else if (type == "MemoryControl") { + m_memorycontrols[name] = new MemoryControl(name); + memory_control_names.push_back (name); + } else { + cerr << "Error: Unknown object type -- " << type << endl; + assert(0); + } + } - DEBUG_MSG(SYSTEM_COMP, MedPrio,"Constructed network"); + for (size_t i=0;i & argv = sys_conf[i].argv; + if (type == "Topology") + m_topologies[name]->init(argv); + } - // CHIP INITIALIZATION - m_chip_vector.setSize(RubyConfig::numberOfChips());// create the vector of pointers to processors - for(int i=0; i & argv = sys_conf[i].argv; + if (type == "SimpleNetwork" || type == "GarnetNetwork" || type == "GarnetNetwork_d"){ + m_network_ptr->init(argv); + } } - // These must be after the chips are constructed + for (size_t i=0;i & argv = sys_conf[i].argv; + if (type == "MemoryControl" ){ + m_memorycontrols[name]->init(argv); + } + } -#if 0 - if (!g_SIMICS) { - if (g_SYNTHETIC_DRIVER && !g_DETERMINISTIC_DRIVER) { - m_driver_ptr = new SyntheticDriver(this); - } else if (!g_SYNTHETIC_DRIVER && g_DETERMINISTIC_DRIVER) { - m_driver_ptr = new DeterministicDriver(this); - } else if (g_SYNTHETIC_DRIVER && g_DETERMINISTIC_DRIVER) { - ERROR_MSG("SYNTHETIC and DETERMINISTIC DRIVERS are exclusive and cannot be both enabled"); - } else { - // normally make tester object, otherwise make an opal interface object. - if (!OpalInterface::isOpalLoaded()) { - m_driver_ptr = new Tester(this); - } else { - m_driver_ptr = new OpalInterface(this); - } + for (size_t i=0;i & argv = sys_conf[i].argv; + if (type == "RubySystem" || type == "Debug") + continue; + else if (type == "SetAssociativeCache") + m_caches[name]->init(argv); + else if (type == "DirectoryMemory") + m_directories[name]->init(argv); + else if (type == "MemoryControl") + continue; + else if (type == "Sequencer") + m_sequencers[name]->init(argv); + else if (type == "DMASequencer") + m_dma_sequencers[name]->init(argv); + else if (type == "Topology") + continue; + else if (type == "SimpleNetwork" || type == "GarnetNetwork" || type == "GarnetNetwork_d") + continue; + else if (type.find("generated") == 0) { + string controller_type = type.substr(11); + m_controllers[name]->init(m_network_ptr, argv); } - } else { - // detect if opal is loaded or not - if (OpalInterface::isOpalLoaded()) { - m_driver_ptr = new OpalInterface(this); - } else { +//added by SS + else if (type == "Tracer") + //m_tracers[name]->init(argv); + m_tracer_ptr->init(argv); + else if (type == "Profiler") + m_profiler_ptr->init(argv, memory_control_names); +// else if (type == "MI_example"){ +// } + else assert(0); - /* Need to allocate a driver here */ - // m_driver_ptr = new SimicsDriver(this); - } } -#endif + +// m_profiler_ptr = new Profiler; + + // calculate system-wide parameters + m_memory_size_bytes = 0; + DirectoryMemory* prev = NULL; + for (map< string, DirectoryMemory*>::const_iterator it = m_directories.begin(); + it != m_directories.end(); it++) { + if (prev != NULL) + assert((*it).second->getSize() == prev->getSize()); // must be equal for proper address mapping + m_memory_size_bytes += (*it).second->getSize(); + prev = (*it).second; + } + m_mem_vec_ptr->setSize(m_memory_size_bytes); + m_memory_size_bits = log_int(m_memory_size_bytes); + +// m_tracer_ptr = new Tracer; DEBUG_MSG(SYSTEM_COMP, MedPrio,"finished initializing"); DEBUG_NEWLINE(SYSTEM_COMP, MedPrio); } -void RubySystem::createDriver() +RubySystem::~RubySystem() { - if (g_SYNTHETIC_DRIVER && !g_DETERMINISTIC_DRIVER) { - cerr << "Creating Synthetic Driver" << endl; - m_driver_ptr = new SyntheticDriver(this); - } else if (!g_SYNTHETIC_DRIVER && g_DETERMINISTIC_DRIVER) { - cerr << "Creating Deterministic Driver" << endl; - m_driver_ptr = new DeterministicDriver(this); + /* + for (int i=0; i < MachineType_base_level(MachineType_NUM); i++) { + for (int j=0; j < RubyConfig::getNumberOfControllersPerType(i); j++ ) { + delete m_controllers[i][j]; } + } + delete m_network_ptr; + delete m_profiler_ptr; + delete m_tracer_ptr; + */ +} + +void RubySystem::printSystemConfig(ostream & out) +{ + out << "RubySystem config:" << endl; + out << " random_seed: " << m_random_seed << endl; + out << " randomization: " << m_randomization << endl; + out << " tech_nm: " << m_tech_nm << endl; + out << " freq_mhz: " << m_freq_mhz << endl; + out << " block_size_bytes: " << m_block_size_bytes << endl; + out << " block_size_bits: " << m_block_size_bits << endl; + out << " memory_size_bytes: " << m_memory_size_bytes << endl; + out << " memory_size_bits: " << m_memory_size_bits << endl; + } -void RubySystem::printConfig(ostream& out) const +void RubySystem::printConfig(ostream& out) { out << "\n================ Begin RubySystem Configuration Print ================\n\n"; - RubyConfig::printConfiguration(out); - out << endl; - getChip(0)->printConfig(out); + // RubyConfig::printConfiguration(out); + // out << endl; + printSystemConfig(out); + for (map::const_iterator it = m_controllers.begin(); + it != m_controllers.end(); it++) { + (*it).second->printConfig(out); + } + for (map::const_iterator it = m_caches.begin(); + it != m_caches.end(); it++) { + (*it).second->printConfig(out); + } + DirectoryMemory::printGlobalConfig(out); + for (map::const_iterator it = m_directories.begin(); + it != m_directories.end(); it++) { + (*it).second->printConfig(out); + } + for (map::const_iterator it = m_sequencers.begin(); + it != m_sequencers.end(); it++) { + (*it).second->printConfig(out); + } + m_network_ptr->printConfig(out); - m_driver_ptr->printConfig(out); m_profiler_ptr->printConfig(out); + out << "\n================ End RubySystem Configuration Print ================\n\n"; } void RubySystem::printStats(ostream& out) { + const time_t T = time(NULL); tm *localTime = localtime(&T); char buf[100]; @@ -174,32 +346,30 @@ void RubySystem::printStats(ostream& out) out << "Real time: " << buf << endl; m_profiler_ptr->printStats(out); - for(int i=0; im_L1Cache_mandatoryQueue_vec[p]->printStats(out); - } - } m_network_ptr->printStats(out); - m_driver_ptr->printStats(out); - Chip::printStats(out); + for (map::const_iterator it = m_controllers.begin(); + it != m_controllers.end(); it++) { + (*it).second->printStats(out); + } } void RubySystem::clearStats() const { + /* m_profiler_ptr->clearStats(); + for (int i=0; iclearStats(); m_network_ptr->clearStats(); - m_driver_ptr->clearStats(); - Chip::clearStats(); - for(int i=0; im_L1Cache_mandatoryQueue_vec[p]->clearStats(); - } - } + for (int i=0; i < MachineType_base_level(MachineType_NUM); i++) + m_controllers[i][0]->clearStats(); + */ } void RubySystem::recordCacheContents(CacheRecorder& tr) const { - for (int i = 0; i < m_chip_vector.size(); i++) { + /* + for (int i = 0; i < m_chip_vector.size(); i++) { for (int m_version = 0; m_version < RubyConfig::numberOfProcsPerChip(); m_version++) { if (Protocol::m_TwoLevelCache) { m_chip_vector[i]->m_L1Cache_L1IcacheMemory_vec[m_version]->setAsInstructionCache(true); @@ -210,6 +380,7 @@ void RubySystem::recordCacheContents(CacheRecorder& tr) const } m_chip_vector[i]->recordCacheContents(tr); } + */ } #ifdef CHECK_COHERENCE @@ -222,7 +393,7 @@ void RubySystem::recordCacheContents(CacheRecorder& tr) const // and "isBlockExclusive" that are specific to that protocol // void RubySystem::checkGlobalCoherenceInvariant(const Address& addr ) { - + /* NodeID exclusive = -1; bool sharedDetected = false; NodeID lastShared = -1; @@ -262,6 +433,7 @@ void RubySystem::checkGlobalCoherenceInvariant(const Address& addr ) { } } } + */ } #endif diff --git a/src/mem/ruby/system/System.hh b/src/mem/ruby/system/System.hh index bc493dd16..40c425ad7 100644 --- a/src/mem/ruby/system/System.hh +++ b/src/mem/ruby/system/System.hh @@ -41,81 +41,129 @@ #ifndef SYSTEM_H #define SYSTEM_H +#include "mem/ruby/system/RubyPort.hh" #include "mem/ruby/common/Global.hh" #include "mem/gems_common/Vector.hh" -#include "mem/ruby/common/Address.hh" -#include "mem/ruby/config/RubyConfig.hh" -#include "mem/protocol/MachineType.hh" -#include "mem/ruby/slicc_interface/AbstractChip.hh" +#include "mem/ruby/eventqueue/RubyEventQueue.hh" +#include class Profiler; class Network; -class Driver; class CacheRecorder; class Tracer; class Sequencer; -class XactIsolationChecker; -class XactCommitArbiter; -class XactVisualizer; -class TransactionInterfaceManager; +class DMASequencer; +class MemoryVector; +class AbstractController; +class MessageBuffer; +class CacheMemory; +class DirectoryMemory; +class Topology; +class MemoryControl; + +struct RubyObjConf { + string type; + string name; + vector argv; + RubyObjConf(string _type, string _name, vector _argv) + : type(_type), name(_name), argv(_argv) + {} +}; class RubySystem { public: - // Constructors - RubySystem(); - RubySystem(Driver* _driver); // used when driver is already instantiated (e.g. M5's RubyMem) - + static RubySystem* create(const vector & sys_conf); // Destructor ~RubySystem(); + // config accessors + static int getRandomSeed() { return m_random_seed; } + static int getRandomization() { return m_randomization; } + static int getTechNm() { return m_tech_nm; } + static int getFreqMhz() { return m_freq_mhz; } + static int getBlockSizeBytes() { return m_block_size_bytes; } + static int getBlockSizeBits() { return m_block_size_bits; } + static uint64 getMemorySizeBytes() { return m_memory_size_bytes; } + static int getMemorySizeBits() { return m_memory_size_bits; } + // Public Methods - int getNumProcessors() { return RubyConfig::numberOfProcessors(); } - int getNumMemories() { return RubyConfig::numberOfMemories(); } - Profiler* getProfiler() { return m_profiler_ptr; } - Driver* getDriver() { assert(m_driver_ptr != NULL); return m_driver_ptr; } + static RubyPort* getPortOnly(const string & name) { + assert(m_ports.count(name) == 1); return m_ports[name]; } + static RubyPort* getPort(const string & name, void (*hit_callback)(int64_t)) { + assert(m_ports.count(name) == 1); m_ports[name]->registerHitCallback(hit_callback); return m_ports[name]; } + static Network* getNetwork() { assert(m_network_ptr != NULL); return m_network_ptr; } + static Topology* getTopology(const string & name) { assert(m_topologies.count(name) == 1); return m_topologies[name]; } + static CacheMemory* getCache(const string & name) { assert(m_caches.count(name) == 1); return m_caches[name]; } + static DirectoryMemory* getDirectory(const string & name) { assert(m_directories.count(name) == 1); return m_directories[name]; } + static MemoryControl* getMemoryControl(const string & name) { assert(m_memorycontrols.count(name) == 1); return m_memorycontrols[name]; } + static Sequencer* getSequencer(const string & name) { assert(m_sequencers.count(name) == 1); return m_sequencers[name]; } + static DMASequencer* getDMASequencer(const string & name) { assert(m_dma_sequencers.count(name) == 1); return m_dma_sequencers[name]; } + static AbstractController* getController(const string & name) { assert(m_controllers.count(name) == 1); return m_controllers[name]; } + + static RubyEventQueue* getEventQueue() { return g_eventQueue_ptr; } + + static int getNumberOfDirectories() { return m_directories.size(); } + static int getNumberOfSequencers() { return m_sequencers.size(); } + + Profiler* getProfiler() {assert(m_profiler_ptr != NULL); return m_profiler_ptr; } Tracer* getTracer() { assert(m_tracer_ptr != NULL); return m_tracer_ptr; } - Network* getNetwork() { assert(m_network_ptr != NULL); return m_network_ptr; } - XactIsolationChecker* getXactIsolationChecker() { assert(m_xact_isolation_checker!= NULL); return m_xact_isolation_checker;} - XactCommitArbiter* getXactCommitArbiter() { assert(m_xact_commit_arbiter!= NULL); return m_xact_commit_arbiter;} - XactVisualizer* getXactVisualizer() { assert(m_xact_visualizer!= NULL); return m_xact_visualizer;} - - AbstractChip* getChip(int chipNumber) const { assert(m_chip_vector[chipNumber] != NULL); return m_chip_vector[chipNumber];} - Sequencer* getSequencer(int procNumber) const { - assert(procNumber < RubyConfig::numberOfProcessors()); - return m_chip_vector[procNumber/RubyConfig::numberOfProcsPerChip()]->getSequencer(procNumber%RubyConfig::numberOfProcsPerChip()); - } - TransactionInterfaceManager* getTransactionInterfaceManager(int procNumber) const { - return m_chip_vector[procNumber/RubyConfig::numberOfProcsPerChip()]->getTransactionInterfaceManager(procNumber%RubyConfig::numberOfProcsPerChip()); - } + static MemoryVector* getMemoryVector() { assert(m_mem_vec_ptr != NULL); return m_mem_vec_ptr;} + void recordCacheContents(CacheRecorder& tr) const; - void printConfig(ostream& out) const; - void printStats(ostream& out); + static void printConfig(ostream& out); + static void printStats(ostream& out); void clearStats() const; + uint64 getInstructionCount(int thread) { return 1; } + static uint64 getCycleCount(int thread) { return g_eventQueue_ptr->getTime(); } + void print(ostream& out) const; + /* #ifdef CHECK_COHERENCE void checkGlobalCoherenceInvariant(const Address& addr); #endif + */ private: - // Private Methods - void init(); - void createDriver(); + // Constructors + RubySystem(const vector & cfg_file); // Private copy constructor and assignment operator RubySystem(const RubySystem& obj); RubySystem& operator=(const RubySystem& obj); + void init(const vector & argv); + + static void printSystemConfig(ostream& out); + +private: + // configuration parameters + static int m_random_seed; + static bool m_randomization; + static int m_tech_nm; + static int m_freq_mhz; + static int m_block_size_bytes; + static int m_block_size_bits; + static uint64 m_memory_size_bytes; + static int m_memory_size_bits; + // Data Members (m_ prefix) - Network* m_network_ptr; - Vector m_chip_vector; - Profiler* m_profiler_ptr; - bool m_preinitialized_driver; - Driver* m_driver_ptr; - Tracer* m_tracer_ptr; - XactIsolationChecker *m_xact_isolation_checker; - XactCommitArbiter *m_xact_commit_arbiter; - XactVisualizer *m_xact_visualizer; + static Network* m_network_ptr; + static map< string, Topology* > m_topologies; + static map< string, RubyPort* > m_ports; + static map< string, CacheMemory* > m_caches; + static map< string, DirectoryMemory* > m_directories; + static map< string, Sequencer* > m_sequencers; + static map< string, DMASequencer* > m_dma_sequencers; + static map< string, AbstractController* > m_controllers; + static map< string, MemoryControl* > m_memorycontrols; + + //added by SS + //static map< string, Tracer* > m_tracers; + + static Profiler* m_profiler_ptr; + static Tracer* m_tracer_ptr; + static MemoryVector* m_mem_vec_ptr; }; // Output operator declaration diff --git a/src/mem/ruby/system/TBETable.hh b/src/mem/ruby/system/TBETable.hh index 2a0c78f06..7d2daa55a 100644 --- a/src/mem/ruby/system/TBETable.hh +++ b/src/mem/ruby/system/TBETable.hh @@ -43,7 +43,6 @@ #include "mem/gems_common/Map.hh" #include "mem/ruby/common/Address.hh" #include "mem/ruby/profiler/Profiler.hh" -#include "mem/ruby/slicc_interface/AbstractChip.hh" #include "mem/ruby/system/System.hh" template @@ -51,19 +50,20 @@ class TBETable { public: // Constructors - TBETable(AbstractChip* chip_ptr); + TBETable(int number_of_TBEs); + // Destructor //~TBETable(); // Public Methods - static void printConfig(ostream& out) { out << "TBEs_per_TBETable: " << NUMBER_OF_TBES << endl; } + void printConfig(ostream& out) { out << "TBEs_per_TBETable: " << m_number_of_TBEs << endl; } bool isPresent(const Address& address) const; void allocate(const Address& address); void deallocate(const Address& address); - bool areNSlotsAvailable(int n) const { return (NUMBER_OF_TBES - m_map.size()) >= n; } + bool areNSlotsAvailable(int n) const { return (m_number_of_TBEs - m_map.size()) >= n; } ENTRY& lookup(const Address& address); const ENTRY& lookup(const Address& address) const; @@ -79,7 +79,9 @@ private: // Data Members (m_prefix) Map m_map; - AbstractChip* m_chip_ptr; + +private: + int m_number_of_TBEs; }; // Output operator declaration @@ -100,11 +102,12 @@ ostream& operator<<(ostream& out, const TBETable& obj) // **************************************************************** + template extern inline -TBETable::TBETable(AbstractChip* chip_ptr) +TBETable::TBETable(int number_of_TBEs) { - m_chip_ptr = chip_ptr; + m_number_of_TBEs = number_of_TBEs; } // PUBLIC METHODS @@ -115,7 +118,7 @@ extern inline bool TBETable::isPresent(const Address& address) const { assert(address == line_address(address)); - assert(m_map.size() <= NUMBER_OF_TBES); + assert(m_map.size() <= m_number_of_TBEs); return m_map.exist(address); } @@ -124,7 +127,7 @@ extern inline void TBETable::allocate(const Address& address) { assert(isPresent(address) == false); - assert(m_map.size() < NUMBER_OF_TBES); + assert(m_map.size() < m_number_of_TBEs); g_system_ptr->getProfiler()->L2tbeUsageSample(m_map.size()); m_map.add(address, ENTRY()); } diff --git a/src/mem/ruby/tester/BarrierGenerator.cc b/src/mem/ruby/tester/BarrierGenerator.cc deleted file mode 100644 index 9dbcf39fd..000000000 --- a/src/mem/ruby/tester/BarrierGenerator.cc +++ /dev/null @@ -1,333 +0,0 @@ - -/* - * Copyright (c) 1999-2008 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. - */ - -/* - * $Id: BarrierGenerator.C 1.3 2005/01/19 13:12:35-06:00 mikem@maya.cs.wisc.edu $ - * - */ - -#include "mem/ruby/tester/BarrierGenerator.hh" -#include "mem/ruby/system/Sequencer.hh" -#include "mem/ruby/system/System.hh" -#include "mem/ruby/config/RubyConfig.hh" -#include "mem/ruby/common/SubBlock.hh" -#include "mem/ruby/tester/SyntheticDriver.hh" -#include "mem/protocol/Chip.hh" - -BarrierGenerator::BarrierGenerator(NodeID node, SyntheticDriver& driver) : - m_driver(driver) -{ - m_status = BarrierGeneratorStatus_Thinking; - m_last_transition = 0; - m_node = node; - m_counter = 0; - proc_counter = 0; - m_local_sense = false; - - m_total_think = 0; - m_think_periods = 0; - - g_eventQueue_ptr->scheduleEvent(this, 1+(random() % 200)); -} - -BarrierGenerator::~BarrierGenerator() -{ -} - -void BarrierGenerator::wakeup() -{ - DEBUG_EXPR(TESTER_COMP, MedPrio, m_node); - DEBUG_EXPR(TESTER_COMP, MedPrio, m_status); - - if (m_status == BarrierGeneratorStatus_Thinking) { - m_barrier_done = false; - m_local_sense = !m_local_sense; - m_status = BarrierGeneratorStatus_Test_Pending; - m_last_transition = g_eventQueue_ptr->getTime(); - initiateTest(); // Test - } else if (m_status == BarrierGeneratorStatus_Test_Waiting) { - m_status = BarrierGeneratorStatus_Test_Pending; - m_last_transition = g_eventQueue_ptr->getTime(); - initiateTest(); // Test - } else if (m_status == BarrierGeneratorStatus_Release_Waiting) { - m_status = BarrierGeneratorStatus_Release_Pending; - m_last_transition = g_eventQueue_ptr->getTime(); - initiateRelease(); // Test - } else if (m_status == BarrierGeneratorStatus_StoreBarrierCounter_Waiting) { - m_status = BarrierGeneratorStatus_StoreBarrierCounter_Pending; - m_last_transition = g_eventQueue_ptr->getTime(); - initiateStoreCtr(); - } else if (m_status == BarrierGeneratorStatus_StoreFlag_Waiting) { - m_status = BarrierGeneratorStatus_StoreFlag_Pending; - m_last_transition = g_eventQueue_ptr->getTime(); - initiateStoreFlag(); - } else if (m_status == BarrierGeneratorStatus_Holding) { - m_status = BarrierGeneratorStatus_Release_Pending; - m_last_transition = g_eventQueue_ptr->getTime(); - initiateRelease(); // Release - } else if (m_status == BarrierGeneratorStatus_Before_Swap) { - m_status = BarrierGeneratorStatus_Swap_Pending; - m_last_transition = g_eventQueue_ptr->getTime(); - initiateSwap(); - } else if (m_status == BarrierGeneratorStatus_SpinFlag_Ready) { - m_status = BarrierGeneratorStatus_SpinFlag_Pending; - m_last_transition = g_eventQueue_ptr->getTime(); - initiateLoadFlag(); - } else { - WARN_EXPR(m_status); - ERROR_MSG("Invalid status"); - } -} - -void BarrierGenerator::performCallback(NodeID proc, SubBlock& data) -{ - Address address = data.getAddress(); - assert(proc == m_node); - - DEBUG_EXPR(TESTER_COMP, LowPrio, proc); - DEBUG_EXPR(TESTER_COMP, LowPrio, m_status); - DEBUG_EXPR(TESTER_COMP, LowPrio, address); - DEBUG_EXPR(TESTER_COMP, LowPrio, data); - - if (m_status == BarrierGeneratorStatus_Test_Pending) { - uint8 dat = data.readByte(); - uint8 lock = dat >> 7; - if (lock == 1) { - // Locked - keep spinning - m_status = BarrierGeneratorStatus_Test_Waiting; - m_last_transition = g_eventQueue_ptr->getTime(); - g_eventQueue_ptr->scheduleEvent(this, waitTime()); - } else { - // Unlocked - try the swap - m_driver.recordTestLatency(g_eventQueue_ptr->getTime() - m_last_transition); - m_status = BarrierGeneratorStatus_Before_Swap; - m_last_transition = g_eventQueue_ptr->getTime(); - g_eventQueue_ptr->scheduleEvent(this, waitTime()); - } - } else if (m_status == BarrierGeneratorStatus_Swap_Pending) { - m_driver.recordSwapLatency(g_eventQueue_ptr->getTime() - m_last_transition); - uint8 dat = data.readByte(); - uint8 lock = dat >> 7; - if (lock == 1) { - // We failed to aquire the lock - m_status = BarrierGeneratorStatus_Test_Waiting; - m_last_transition = g_eventQueue_ptr->getTime(); - g_eventQueue_ptr->scheduleEvent(this, waitTime()); - } else { - // We acquired the lock - dat = dat | 0x80; - data.writeByte(dat); - m_status = BarrierGeneratorStatus_StoreBarrierCounter_Waiting; - m_last_transition = g_eventQueue_ptr->getTime(); - DEBUG_MSG(TESTER_COMP, HighPrio, "Acquired"); - DEBUG_EXPR(TESTER_COMP, HighPrio, proc); - DEBUG_EXPR(TESTER_COMP, HighPrio, g_eventQueue_ptr->getTime()); - // g_eventQueue_ptr->scheduleEvent(this, holdTime()); - - g_eventQueue_ptr->scheduleEvent(this, 1); - - // initiateLoadCtr(); - } - } else if (m_status == BarrierGeneratorStatus_StoreBarrierCounter_Pending) { - - // if value == p, reset counter and set local sense flag - uint8 ctr = data.readByte(); - //uint8 sense = ctr >> 4; - ctr = ctr & 0x0F; - - ctr++; - data.writeByte( ctr | 0x80); // store counter and lock - - //cout << m_node << " incremented Barrier_ctr to " << (int)ctr << ", " << data << "\n"; - - if (ctr == (uint8) 16) { - - data.writeByte( 0x0 ); - m_status = BarrierGeneratorStatus_StoreFlag_Waiting; - m_barrier_done = true; - - g_eventQueue_ptr->scheduleEvent(this, 1); - } - else { - - m_status = BarrierGeneratorStatus_Release_Waiting; - g_eventQueue_ptr->scheduleEvent(this, 1); - } - } else if (m_status == BarrierGeneratorStatus_StoreFlag_Pending) { - - // write flag - if (m_local_sense) { - data.writeByte( 0x01 ); - } - else { - data.writeByte( 0x00 ); - } - - m_status = BarrierGeneratorStatus_Release_Waiting; - g_eventQueue_ptr->scheduleEvent(this, 1); - - } else if (m_status == BarrierGeneratorStatus_Release_Pending) { - m_driver.recordReleaseLatency(g_eventQueue_ptr->getTime() - m_last_transition); - // We're releasing the lock - uint8 dat = data.readByte(); - dat = dat & 0x7F; - data.writeByte(dat); - - if (m_barrier_done) { - m_counter++; - proc_counter++; - if (m_counter < g_tester_length) { - m_status = BarrierGeneratorStatus_Thinking; - m_last_transition = g_eventQueue_ptr->getTime(); - g_eventQueue_ptr->scheduleEvent(this, thinkTime()); - } else { - - m_driver.reportDone(proc_counter, m_node); - m_last_transition = g_eventQueue_ptr->getTime(); - } - } - else { - m_status = BarrierGeneratorStatus_SpinFlag_Ready; - m_last_transition = g_eventQueue_ptr->getTime(); - g_eventQueue_ptr->scheduleEvent(this, waitTime()); - } - } else if (m_status == BarrierGeneratorStatus_SpinFlag_Pending) { - - uint8 sense = data.readByte(); - - - if (sense != m_local_sense) { - m_status = BarrierGeneratorStatus_SpinFlag_Ready; - m_last_transition = g_eventQueue_ptr->getTime(); - g_eventQueue_ptr->scheduleEvent(this, waitTime()); - } - else { - m_counter++; - proc_counter++; - if (m_counter < g_tester_length) { - m_status = BarrierGeneratorStatus_Thinking; - m_last_transition = g_eventQueue_ptr->getTime(); - g_eventQueue_ptr->scheduleEvent(this, thinkTime()); - } else { - m_driver.reportDone(proc_counter, m_node); - m_status = BarrierGeneratorStatus_Done; - m_last_transition = g_eventQueue_ptr->getTime(); - } - } - - } else { - WARN_EXPR(m_status); - ERROR_MSG("Invalid status"); - } -} - -int BarrierGenerator::thinkTime() -{ - int ret; - float ratio = g_think_fudge_factor; - - // return 400; - - if (ratio == 0) { - return g_think_time; - } - - int r = random(); - int x = (int) ( (float)g_think_time*ratio*2.0); - int mod = r % x; - - - int rand = ( mod+1 - ((float)g_think_time*ratio) ); - - ret = (g_think_time + rand); - - m_total_think += ret; - m_think_periods++; - - return ret; -} - -int BarrierGenerator::waitTime() const -{ - return g_wait_time; -} - - -void BarrierGenerator::initiateTest() -{ - DEBUG_MSG(TESTER_COMP, MedPrio, "initiating Test"); - sequencer()->makeRequest(CacheMsg(Address(0x40), CacheRequestType_LD, Address(1), AccessModeType_UserMode, 1, PrefetchBit_No, 0, false)); -} - -void BarrierGenerator::initiateSwap() -{ - DEBUG_MSG(TESTER_COMP, MedPrio, "initiating Swap"); - sequencer()->makeRequest(CacheMsg(Address(0x40), CacheRequestType_ATOMIC, Address(2), AccessModeType_UserMode, 1, PrefetchBit_No, 0, false)); -} - -void BarrierGenerator::initiateRelease() -{ - DEBUG_MSG(TESTER_COMP, MedPrio, "initiating Release"); - sequencer()->makeRequest(CacheMsg(Address(0x40), CacheRequestType_ST, Address(3), AccessModeType_UserMode, 1, PrefetchBit_No, 0, false)); -} - -void BarrierGenerator::initiateLoadCtr() -{ - DEBUG_MSG(TESTER_COMP, MedPrio, "initiating load of barrier counter"); - sequencer()->makeRequest(CacheMsg(Address(0x40), CacheRequestType_LD, Address(3), AccessModeType_UserMode, 1, PrefetchBit_No, 0, false)); -} - -void BarrierGenerator::initiateStoreCtr() -{ - DEBUG_MSG(TESTER_COMP, MedPrio, "initiating load of barrier counter"); - sequencer()->makeRequest(CacheMsg(Address(0x40), CacheRequestType_ST, Address(3), AccessModeType_UserMode, 1, PrefetchBit_No, 0, false)); -} - -void BarrierGenerator::initiateStoreFlag() -{ - DEBUG_MSG(TESTER_COMP, MedPrio, "initiating load of barrier counter"); - sequencer()->makeRequest(CacheMsg(Address(0x00), CacheRequestType_ST, Address(3), AccessModeType_UserMode, 1, PrefetchBit_No, 0, false)); -} - -void BarrierGenerator::initiateLoadFlag() -{ - DEBUG_MSG(TESTER_COMP, MedPrio, "initiating load of barrier counter"); - sequencer()->makeRequest(CacheMsg(Address(0x00), CacheRequestType_LD, Address(3), AccessModeType_UserMode, 1, PrefetchBit_No, 0, false)); -} - - -Sequencer* BarrierGenerator::sequencer() const -{ - return g_system_ptr->getChip(m_node/RubyConfig::numberOfProcsPerChip())->getSequencer(m_node%RubyConfig::numberOfProcsPerChip()); -} - -void BarrierGenerator::print(ostream& out) const -{ -} - diff --git a/src/mem/ruby/tester/BarrierGenerator.hh b/src/mem/ruby/tester/BarrierGenerator.hh deleted file mode 100644 index e0fa497da..000000000 --- a/src/mem/ruby/tester/BarrierGenerator.hh +++ /dev/null @@ -1,138 +0,0 @@ - -/* - * Copyright (c) 1999-2008 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. - */ - -/* - * $Id$ - * - * Description: - * - */ - -#ifndef BARRIERGENERATOR_H -#define BARRIERGENERATOR_H - -#include "mem/ruby/common/Global.hh" -#include "mem/ruby/common/Consumer.hh" -#include "mem/ruby/system/NodeID.hh" -#include "mem/ruby/common/Address.hh" - -class Sequencer; -class SubBlock; -class SyntheticDriver; - - -enum BarrierGeneratorStatus { - BarrierGeneratorStatus_FIRST, - BarrierGeneratorStatus_Thinking = BarrierGeneratorStatus_FIRST, - BarrierGeneratorStatus_Test_Pending, - BarrierGeneratorStatus_Test_Waiting, - BarrierGeneratorStatus_Before_Swap, - BarrierGeneratorStatus_Swap_Pending, - BarrierGeneratorStatus_Holding, - BarrierGeneratorStatus_Release_Pending, - BarrierGeneratorStatus_Release_Waiting, - BarrierGeneratorStatus_StoreFlag_Waiting, - BarrierGeneratorStatus_StoreFlag_Pending, - BarrierGeneratorStatus_Done, - BarrierGeneratorStatus_SpinFlag_Ready, - BarrierGeneratorStatus_SpinFlag_Pending, - BarrierGeneratorStatus_LoadBarrierCounter_Pending, - BarrierGeneratorStatus_StoreBarrierCounter_Pending, - BarrierGeneratorStatus_StoreBarrierCounter_Waiting, - BarrierGeneratorStatus_NUM -}; - - -// UNCOMMENT THIS FOR A SINGLE WORK QUEUE -// static int m_counter; - -class BarrierGenerator : public Consumer { -public: - // Constructors - BarrierGenerator(NodeID node, SyntheticDriver& driver); - - // Destructor - ~BarrierGenerator(); - - // Public Methods - void wakeup(); - void performCallback(NodeID proc, SubBlock& data); - - void print(ostream& out) const; -private: - // Private Methods - int thinkTime() ; - int waitTime() const; - void initiateTest(); - void initiateSwap(); - void initiateRelease(); - void initiateLoadCtr(); - void initiateStoreCtr(); - void initiateLoadFlag(); - void initiateStoreFlag(); - Sequencer* sequencer() const; - - // Private copy constructor and assignment operator - BarrierGenerator(const BarrierGenerator& obj); - BarrierGenerator& operator=(const BarrierGenerator& obj); - - // Data Members (m_ prefix) - SyntheticDriver& m_driver; - NodeID m_node; - BarrierGeneratorStatus m_status; - int proc_counter; - - int m_counter; - - bool m_local_sense; - bool m_barrier_done; - - Time m_last_transition; - Address m_address; - - int m_total_think; - int m_think_periods; -}; - -// Output operator declaration -ostream& operator<<(ostream& out, const BarrierGenerator& obj); - -// ******************* Definitions ******************* - -// Output operator definition -extern inline -ostream& operator<<(ostream& out, const BarrierGenerator& obj) -{ - obj.print(out); - out << flush; - return out; -} - -#endif //REQUESTGENERATOR_H - diff --git a/src/mem/ruby/tester/Check.cc b/src/mem/ruby/tester/Check.cc deleted file mode 100644 index 7896b572a..000000000 --- a/src/mem/ruby/tester/Check.cc +++ /dev/null @@ -1,310 +0,0 @@ - -/* - * Copyright (c) 1999-2008 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. - */ - -/* - * $Id$ - * - */ - -#include "mem/ruby/tester/Check.hh" -#include "mem/ruby/system/Sequencer.hh" -#include "mem/ruby/system/System.hh" -#include "mem/ruby/common/SubBlock.hh" -#include "mem/protocol/Chip.hh" -#include "mem/packet.hh" - -Check::Check(const Address& address, const Address& pc) -{ - m_status = TesterStatus_Idle; - - pickValue(); - pickInitiatingNode(); - changeAddress(address); - m_pc = pc; - m_access_mode = AccessModeType(random() % AccessModeType_NUM); - m_store_count = 0; -} - -void Check::initiate() -{ - DEBUG_MSG(TESTER_COMP, MedPrio, "initiating"); - DEBUG_EXPR(TESTER_COMP, MedPrio, *this); - - // current CMP protocol doesn't support prefetches - if (!Protocol::m_CMP && (random() & 0xf) == 0) { // 1 in 16 chance - initiatePrefetch(); // Prefetch from random processor - } - - if(m_status == TesterStatus_Idle) { - initiateAction(); - } else if(m_status == TesterStatus_Ready) { - initiateCheck(); - } else { - // Pending - do nothing - DEBUG_MSG(TESTER_COMP, MedPrio, "initiating action/check - failed: action/check is pending\n"); - } -} - -void Check::initiatePrefetch(Sequencer* targetSequencer_ptr) -{ - DEBUG_MSG(TESTER_COMP, MedPrio, "initiating prefetch"); - - CacheRequestType type; - if ((random() & 0x7) != 0) { // 1 in 8 chance - if ((random() & 0x1) == 0) { // 50% chance - type = CacheRequestType_LD; - } else { - type = CacheRequestType_IFETCH; - } - } else { - type = CacheRequestType_ST; - } - - Addr data_addr = m_address.getAddress(); - Addr pc_addr = m_pc.getAddress(); - Request request(0, data_addr, 0, Flags(Request::PREFETCH), pc_addr, 0, 0); - MemCmd::Command command; - if (type == CacheRequestType_IFETCH) { - command = MemCmd::ReadReq; - request.setFlags(Request::INST_FETCH); - } else if (type == CacheRequestType_LD || type == CacheRequestType_IFETCH) { - command = MemCmd::ReadReq; - } else if (type == CacheRequestType_ST) { - command = MemCmd::WriteReq; - } else if (type == CacheRequestType_ATOMIC) { - command = MemCmd::SwapReq; // TODO -- differentiate between atomic types - } else { - panic("Cannot convert request to packet"); - } - - Packet pkt(&request, command, 0); // TODO -- make dest a real NodeID - - assert(targetSequencer_ptr != NULL); - if (targetSequencer_ptr->isReady(&pkt)) { - targetSequencer_ptr->makeRequest(&pkt); - } -} - -void Check::initiatePrefetch() -{ - // Any sequencer can issue a prefetch for this address - Sequencer* targetSequencer_ptr = g_system_ptr->getChip(random() % RubyConfig::numberOfChips())->getSequencer(random() % RubyConfig::numberOfProcsPerChip()); - assert(targetSequencer_ptr != NULL); - initiatePrefetch(targetSequencer_ptr); -} - -void Check::initiateAction() -{ - DEBUG_MSG(TESTER_COMP, MedPrio, "initiating Action"); - assert(m_status == TesterStatus_Idle); - - CacheRequestType type = CacheRequestType_ST; - if ((random() & 0x1) == 0) { // 50% chance - type = CacheRequestType_ATOMIC; - } - - Addr data_addr = m_address.getAddress()+m_store_count; - Addr pc_addr = m_pc.getAddress(); - Request request(0, data_addr, 1, Flags(), pc_addr, 0, 0); - MemCmd::Command command; - if (type == CacheRequestType_IFETCH) { - command = MemCmd::ReadReq; - request.setFlags(Request::INST_FETCH); - } else if (type == CacheRequestType_LD || type == CacheRequestType_IFETCH) { - command = MemCmd::ReadReq; - } else if (type == CacheRequestType_ST) { - command = MemCmd::WriteReq; - } else if (type == CacheRequestType_ATOMIC) { - command = MemCmd::SwapReq; // TODO -- differentiate between atomic types - } else { - panic("Cannot convert request to packet"); - } - - Packet pkt(&request, command, 0); // TODO -- make dest a real NodeID - - Sequencer* sequencer_ptr = initiatingSequencer(); - if (sequencer_ptr->isReady(&pkt) == false) { - DEBUG_MSG(TESTER_COMP, MedPrio, "failed to initiate action - sequencer not ready\n"); - } else { - DEBUG_MSG(TESTER_COMP, MedPrio, "initiating action - successful\n"); - DEBUG_EXPR(TESTER_COMP, MedPrio, m_status); - m_status = TesterStatus_Action_Pending; - - sequencer_ptr->makeRequest(&pkt); - } - DEBUG_EXPR(TESTER_COMP, MedPrio, m_status); -} - -void Check::initiateCheck() -{ - DEBUG_MSG(TESTER_COMP, MedPrio, "initiating Check"); - assert(m_status == TesterStatus_Ready); - - CacheRequestType type = CacheRequestType_LD; - if ((random() & 0x1) == 0) { // 50% chance - type = CacheRequestType_IFETCH; - } - - - Addr data_addr = m_address.getAddress()+m_store_count; - Addr pc_addr = m_pc.getAddress(); - Request request(0, data_addr, CHECK_SIZE, Flags(), pc_addr, 0, 0); - MemCmd::Command command; - if (type == CacheRequestType_IFETCH) { - command = MemCmd::ReadReq; - request.setFlags(Request::INST_FETCH); - } else if (type == CacheRequestType_LD || type == CacheRequestType_IFETCH) { - command = MemCmd::ReadReq; - } else if (type == CacheRequestType_ST) { - command = MemCmd::WriteReq; - } else if (type == CacheRequestType_ATOMIC) { - command = MemCmd::SwapReq; // TODO -- differentiate between atomic types - } else { - panic("Cannot convert request to packet"); - } - - Packet pkt(&request, command, 0); // TODO -- make dest a real NodeID - - Sequencer* sequencer_ptr = initiatingSequencer(); - if (sequencer_ptr->isReady(&pkt) == false) { - DEBUG_MSG(TESTER_COMP, MedPrio, "failed to initiate check - sequencer not ready\n"); - } else { - DEBUG_MSG(TESTER_COMP, MedPrio, "initiating check - successful\n"); - DEBUG_MSG(TESTER_COMP, MedPrio, m_status); - m_status = TesterStatus_Check_Pending; - - sequencer_ptr->makeRequest(&pkt); - } - DEBUG_MSG(TESTER_COMP, MedPrio, m_status); -} - -void Check::performCallback(NodeID proc, SubBlock& data) -{ - Address address = data.getAddress(); - // assert(getAddress() == address); // This isn't exactly right since we now have multi-byte checks - assert(getAddress().getLineAddress() == address.getLineAddress()); - - DEBUG_MSG(TESTER_COMP, MedPrio, "Callback"); - DEBUG_EXPR(TESTER_COMP, MedPrio, *this); - - if (m_status == TesterStatus_Action_Pending) { - DEBUG_MSG(TESTER_COMP, MedPrio, "Action callback"); - // Perform store - data.setByte(0, m_value+m_store_count); // We store one byte at a time - m_store_count++; - - if (m_store_count == CHECK_SIZE) { - m_status = TesterStatus_Ready; - } else { - m_status = TesterStatus_Idle; - } - } else if (m_status == TesterStatus_Check_Pending) { - DEBUG_MSG(TESTER_COMP, MedPrio, "Check callback"); - // Perform load/check - for(int byte_number=0; byte_numbergetTime()); - ERROR_MSG("Action/check failure"); - } - } - DEBUG_MSG(TESTER_COMP, HighPrio, "Action/check success:"); - DEBUG_EXPR(TESTER_COMP, HighPrio, *this); - DEBUG_EXPR(TESTER_COMP, MedPrio, data); - - m_status = TesterStatus_Idle; - pickValue(); - - } else { - WARN_EXPR(*this); - WARN_EXPR(proc); - WARN_EXPR(data); - WARN_EXPR(m_status); - WARN_EXPR(g_eventQueue_ptr->getTime()); - ERROR_MSG("Unexpected TesterStatus"); - } - - DEBUG_EXPR(TESTER_COMP, MedPrio, proc); - DEBUG_EXPR(TESTER_COMP, MedPrio, data); - DEBUG_EXPR(TESTER_COMP, MedPrio, getAddress().getLineAddress()); - DEBUG_MSG(TESTER_COMP, MedPrio, "Callback done"); - DEBUG_EXPR(TESTER_COMP, MedPrio, *this); -} - -void Check::changeAddress(const Address& address) -{ - assert((m_status == TesterStatus_Idle) || (m_status == TesterStatus_Ready)); - m_status = TesterStatus_Idle; - m_address = address; - m_store_count = 0; -} - -Sequencer* Check::initiatingSequencer() const -{ - return g_system_ptr->getChip(m_initiatingNode/RubyConfig::numberOfProcsPerChip())->getSequencer(m_initiatingNode%RubyConfig::numberOfProcsPerChip()); -} - -void Check::pickValue() -{ - assert(m_status == TesterStatus_Idle); - m_status = TesterStatus_Idle; - // DEBUG_MSG(TESTER_COMP, MedPrio, m_status); - DEBUG_MSG(TESTER_COMP, MedPrio, *this); - m_value = random() & 0xff; // One byte - // DEBUG_MSG(TESTER_COMP, MedPrio, m_value); - DEBUG_MSG(TESTER_COMP, MedPrio, *this); - m_store_count = 0; -} - -void Check::pickInitiatingNode() -{ - assert((m_status == TesterStatus_Idle) || (m_status == TesterStatus_Ready)); - m_status = TesterStatus_Idle; - DEBUG_MSG(TESTER_COMP, MedPrio, m_status); - m_initiatingNode = (random() % RubyConfig::numberOfProcessors()); - DEBUG_MSG(TESTER_COMP, MedPrio, m_initiatingNode); - m_store_count = 0; -} - -void Check::print(ostream& out) const -{ - out << "[" - << m_address << ", value: " - << (int) m_value << ", status: " - << m_status << ", initiating node: " - << m_initiatingNode << ", store_count: " - << m_store_count - << "]" << flush; -} diff --git a/src/mem/ruby/tester/Check.hh b/src/mem/ruby/tester/Check.hh deleted file mode 100644 index 8f08b3f40..000000000 --- a/src/mem/ruby/tester/Check.hh +++ /dev/null @@ -1,107 +0,0 @@ - -/* - * Copyright (c) 1999-2008 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. - */ - -/* - * $Id$ - * - * Description: - * - */ - -#ifndef CHECK_H -#define CHECK_H - -#include "mem/ruby/common/Global.hh" -#include "mem/ruby/common/Address.hh" -#include "mem/ruby/system/NodeID.hh" -#include "mem/protocol/TesterStatus.hh" -#include "mem/protocol/AccessModeType.hh" -class Sequencer; -class SubBlock; - -const int CHECK_SIZE_BITS = 2; -const int CHECK_SIZE = (1<; - physical_address_t physical = 0; - Address address; - - const int size1 = 32; - const int size2 = 100; - - // The first set is to get some false sharing - physical = 1000; - for (int i=0; iexist(Address(address.getAddress()+i))) { - // A mapping for this byte already existed, discard the entire check - return; - } - } - - Check* check_ptr = new Check(address, Address(100+m_check_vector.size())); - for (int i=0; iadd(Address(address.getAddress()+i), check_ptr); - } - m_check_vector.insertAtBottom(check_ptr); -} - -Check* CheckTable::getRandomCheck() -{ - return m_check_vector[random() % m_check_vector.size()]; -} - -Check* CheckTable::getCheck(const Address& address) -{ - DEBUG_MSG(TESTER_COMP, MedPrio, "Looking for check by address"); - DEBUG_EXPR(TESTER_COMP, MedPrio, address); - - if (m_lookup_map_ptr->exist(address)) { - Check* check = m_lookup_map_ptr->lookup(address); - assert(check != NULL); - return check; - } else { - return NULL; - } -} - -void CheckTable::print(ostream& out) const -{ -} diff --git a/src/mem/ruby/tester/CheckTable.hh b/src/mem/ruby/tester/CheckTable.hh deleted file mode 100644 index a7f486315..000000000 --- a/src/mem/ruby/tester/CheckTable.hh +++ /dev/null @@ -1,93 +0,0 @@ - -/* - * Copyright (c) 1999-2008 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. - */ - -/* - * $Id$ - * - * Description: - * - */ - -#ifndef CHECKTABLE_H -#define CHECKTABLE_H - -#include "mem/ruby/common/Global.hh" -#include "mem/gems_common/Vector.hh" - -class Address; -class Check; -template class Map; - -class CheckTable { -public: - // Constructors - CheckTable(); - - // Destructor - ~CheckTable(); - - // Public Methods - - Check* getRandomCheck(); - Check* getCheck(const Address& address); - - // bool isPresent(const Address& address) const; - // void removeCheckFromTable(const Address& address); - // bool isTableFull() const; - // Need a method to select a check or retrieve a check - - void print(ostream& out) const; -private: - // Private Methods - void addCheck(const Address& address); - - // Private copy constructor and assignment operator - CheckTable(const CheckTable& obj); - CheckTable& operator=(const CheckTable& obj); - - // Data Members (m_ prefix) - Vector m_check_vector; - Map* m_lookup_map_ptr; -}; - -// Output operator declaration -ostream& operator<<(ostream& out, const CheckTable& obj); - -// ******************* Definitions ******************* - -// Output operator definition -extern inline -ostream& operator<<(ostream& out, const CheckTable& obj) -{ - obj.print(out); - out << flush; - return out; -} - -#endif //CHECKTABLE_H diff --git a/src/mem/ruby/tester/DetermGETXGenerator.cc b/src/mem/ruby/tester/DetermGETXGenerator.cc index e4d8addd2..6692fb80c 100644 --- a/src/mem/ruby/tester/DetermGETXGenerator.cc +++ b/src/mem/ruby/tester/DetermGETXGenerator.cc @@ -37,26 +37,23 @@ #include "mem/ruby/tester/DetermGETXGenerator.hh" #include "mem/protocol/DetermGETXGeneratorStatus.hh" -#include "mem/protocol/LockStatus.hh" -#include "mem/ruby/system/Sequencer.hh" -#include "mem/ruby/system/System.hh" -#include "mem/ruby/config/RubyConfig.hh" -#include "mem/ruby/common/SubBlock.hh" #include "mem/ruby/tester/DeterministicDriver.hh" -#include "mem/protocol/Chip.hh" -#include "mem/packet.hh" +#include "mem/ruby/tester/Global_Tester.hh" +#include "mem/ruby/tester/SpecifiedGenerator.hh" +//#include "DMAController.hh" +#include "mem/ruby/libruby.hh" -DetermGETXGenerator::DetermGETXGenerator(NodeID node, DeterministicDriver& driver) : - m_driver(driver) + +DetermGETXGenerator::DetermGETXGenerator(NodeID node, DeterministicDriver * driver) { m_status = DetermGETXGeneratorStatus_Thinking; m_last_transition = 0; m_node = node; m_address = Address(9999); // initialize to null value m_counter = 0; - + parent_driver = driver; // don't know exactly when this node needs to request so just guess randomly - g_eventQueue_ptr->scheduleEvent(this, 1+(random() % 200)); + parent_driver->eventQueue->scheduleEvent(this, 1+(random() % 200)); } DetermGETXGenerator::~DetermGETXGenerator() @@ -70,13 +67,13 @@ void DetermGETXGenerator::wakeup() // determine if this node is next for the GETX round robin request if (m_status == DetermGETXGeneratorStatus_Thinking) { - if (m_driver.isStoreReady(m_node)) { + if (parent_driver->isStoreReady(m_node)) { pickAddress(); m_status = DetermGETXGeneratorStatus_Store_Pending; // Store Pending - m_last_transition = g_eventQueue_ptr->getTime(); + m_last_transition = parent_driver->eventQueue->getTime(); initiateStore(); // GETX } else { // I'll check again later - g_eventQueue_ptr->scheduleEvent(this, thinkTime()); + parent_driver->eventQueue->scheduleEvent(this, thinkTime()); } } else { WARN_EXPR(m_status); @@ -85,31 +82,28 @@ void DetermGETXGenerator::wakeup() } -void DetermGETXGenerator::performCallback(NodeID proc, SubBlock& data) +void DetermGETXGenerator::performCallback(NodeID proc, Address address) { - Address address = data.getAddress(); assert(proc == m_node); assert(address == m_address); DEBUG_EXPR(TESTER_COMP, LowPrio, proc); DEBUG_EXPR(TESTER_COMP, LowPrio, m_status); DEBUG_EXPR(TESTER_COMP, LowPrio, address); - DEBUG_EXPR(TESTER_COMP, LowPrio, data); if (m_status == DetermGETXGeneratorStatus_Store_Pending) { - m_driver.recordStoreLatency(g_eventQueue_ptr->getTime() - m_last_transition); - data.writeByte(m_node); - m_driver.storeCompleted(m_node, data.getAddress()); // advance the store queue + parent_driver->recordStoreLatency(parent_driver->eventQueue->getTime() - m_last_transition); + parent_driver->storeCompleted(m_node, address); // advance the store queue m_counter++; - if (m_counter < g_tester_length) { + if (m_counter < parent_driver->m_tester_length) { m_status = DetermGETXGeneratorStatus_Thinking; - m_last_transition = g_eventQueue_ptr->getTime(); - g_eventQueue_ptr->scheduleEvent(this, waitTime()); + m_last_transition = parent_driver->eventQueue->getTime(); + parent_driver->eventQueue->scheduleEvent(this, waitTime()); } else { - m_driver.reportDone(); + parent_driver->reportDone(); m_status = DetermGETXGeneratorStatus_Done; - m_last_transition = g_eventQueue_ptr->getTime(); + m_last_transition = parent_driver->eventQueue->getTime(); } } else { @@ -120,38 +114,40 @@ void DetermGETXGenerator::performCallback(NodeID proc, SubBlock& data) int DetermGETXGenerator::thinkTime() const { - return g_think_time; + return parent_driver->m_think_time; } int DetermGETXGenerator::waitTime() const { - return g_wait_time; + return parent_driver->m_wait_time; } void DetermGETXGenerator::pickAddress() { assert(m_status == DetermGETXGeneratorStatus_Thinking); - m_address = m_driver.getNextStoreAddr(m_node); + m_address = parent_driver->getNextStoreAddr(m_node); } void DetermGETXGenerator::initiateStore() { DEBUG_MSG(TESTER_COMP, MedPrio, "initiating Store"); - Addr data_addr = m_address.getAddress(); - Request request(0, data_addr, 1, Flags(), 3, 0, 0); - MemCmd::Command command; - command = MemCmd::WriteReq; + uint8_t *write_data = new uint8_t[64]; + for(int i=0; i < 64; i++) { + write_data[i] = m_node; + } + + char name [] = "Sequencer_"; + char port_name [13]; + sprintf(port_name, "%s%d", name, m_node); - Packet pkt(&request, command, 0); // TODO -- make dest a real NodeID + int64_t request_id = libruby_issue_request(libruby_get_port_by_name(port_name), RubyRequest(m_address.getAddress(), write_data, 64, 0, RubyRequestType_ST, RubyAccessMode_Supervisor)); - sequencer()->makeRequest(&pkt); -} + // delete [] write_data; -Sequencer* DetermGETXGenerator::sequencer() const -{ - return g_system_ptr->getChip(m_node/RubyConfig::numberOfProcsPerChip())->getSequencer(m_node%RubyConfig::numberOfProcsPerChip()); + ASSERT(parent_driver->requests.find(request_id) == parent_driver->requests.end()); + parent_driver->requests.insert(make_pair(request_id, make_pair(m_node, m_address))); } void DetermGETXGenerator::print(ostream& out) const diff --git a/src/mem/ruby/tester/DetermGETXGenerator.hh b/src/mem/ruby/tester/DetermGETXGenerator.hh index 1f5b67653..82e616e4b 100644 --- a/src/mem/ruby/tester/DetermGETXGenerator.hh +++ b/src/mem/ruby/tester/DetermGETXGenerator.hh @@ -40,28 +40,26 @@ #ifndef DETERMGETXGENERATOR_H #define DETERMGETXGENERATOR_H -#include "mem/ruby/common/Global.hh" +#include "mem/ruby/tester/Global_Tester.hh" #include "mem/ruby/common/Consumer.hh" #include "mem/protocol/DetermGETXGeneratorStatus.hh" -#include "mem/ruby/system/NodeID.hh" -#include "mem/ruby/common/Address.hh" +#include "Address_Tester.hh" #include "mem/ruby/tester/SpecifiedGenerator.hh" -class Sequencer; -class SubBlock; class DeterministicDriver; +class DMAController; class DetermGETXGenerator : public SpecifiedGenerator { public: // Constructors - DetermGETXGenerator(NodeID node, DeterministicDriver& driver); + DetermGETXGenerator(NodeID node, DeterministicDriver * driver); // Destructor ~DetermGETXGenerator(); // Public Methods void wakeup(); - void performCallback(NodeID proc, SubBlock& data); + void performCallback(NodeID proc, Address address); void print(ostream& out) const; private: @@ -69,20 +67,21 @@ private: int thinkTime() const; int waitTime() const; void initiateStore(); + void initiateDMA(); void pickAddress(); - Sequencer* sequencer() const; + DMAController* dma() const; // copy constructor and assignment operator DetermGETXGenerator(const DetermGETXGenerator& obj); DetermGETXGenerator& operator=(const DetermGETXGenerator& obj); + DeterministicDriver * parent_driver; // Data Members (m_ prefix) DetermGETXGeneratorStatus m_status; int m_counter; Address m_address; NodeID m_node; - DeterministicDriver& m_driver; Time m_last_transition; }; diff --git a/src/mem/ruby/tester/DetermInvGenerator.cc b/src/mem/ruby/tester/DetermInvGenerator.cc index bafaa18ae..eebe18057 100644 --- a/src/mem/ruby/tester/DetermInvGenerator.cc +++ b/src/mem/ruby/tester/DetermInvGenerator.cc @@ -38,13 +38,10 @@ #include "mem/ruby/tester/DetermInvGenerator.hh" #include "mem/protocol/DetermInvGeneratorStatus.hh" -#include "mem/protocol/LockStatus.hh" -#include "mem/ruby/system/Sequencer.hh" -#include "mem/ruby/system/System.hh" -#include "mem/ruby/config/RubyConfig.hh" -#include "mem/ruby/common/SubBlock.hh" #include "mem/ruby/tester/DeterministicDriver.hh" -#include "mem/protocol/Chip.hh" +#include "mem/ruby/tester/Global_Tester.hh" +//#include "DMAController.hh" +#include "mem/ruby/libruby.hh" DetermInvGenerator::DetermInvGenerator(NodeID node, DeterministicDriver& driver) : m_driver(driver) @@ -54,9 +51,8 @@ DetermInvGenerator::DetermInvGenerator(NodeID node, DeterministicDriver& driver) m_node = node; m_address = Address(9999); // initiate to a NULL value m_counter = 0; - // don't know exactly when this node needs to request so just guess randomly - g_eventQueue_ptr->scheduleEvent(this, 1+(random() % 200)); + m_driver.eventQueue->scheduleEvent(this, 1+(random() % 200)); } DetermInvGenerator::~DetermInvGenerator() @@ -74,23 +70,23 @@ void DetermInvGenerator::wakeup() if (m_driver.isLoadReady(m_node) && m_counter == m_driver.getStoresCompleted()) { pickLoadAddress(); m_status = DetermInvGeneratorStatus_Load_Pending; // Load Pending - m_last_transition = g_eventQueue_ptr->getTime(); + m_last_transition = m_driver.eventQueue->getTime(); initiateLoad(); // GETS } else { // I'll check again later - g_eventQueue_ptr->scheduleEvent(this, thinkTime()); + m_driver.eventQueue->scheduleEvent(this, thinkTime()); } } else if (m_status == DetermInvGeneratorStatus_Load_Complete) { if (m_driver.isStoreReady(m_node, m_address)) { // do a store in this transaction or start the next one if (m_driver.isLoadReady((0), m_address)) { // everyone is in S for this address i.e. back to node 0 m_status = DetermInvGeneratorStatus_Store_Pending; - m_last_transition = g_eventQueue_ptr->getTime(); + m_last_transition = m_driver.eventQueue->getTime(); initiateStore(); // GETX } else { // I'm next, I just have to wait for all loads to complete - g_eventQueue_ptr->scheduleEvent(this, thinkTime()); + m_driver.eventQueue->scheduleEvent(this, thinkTime()); } } else { // I'm not next to store, go back to thinking m_status = DetermInvGeneratorStatus_Thinking; - g_eventQueue_ptr->scheduleEvent(this, thinkTime()); + m_driver.eventQueue->scheduleEvent(this, thinkTime()); } } else { WARN_EXPR(m_status); @@ -99,48 +95,48 @@ void DetermInvGenerator::wakeup() } -void DetermInvGenerator::performCallback(NodeID proc, SubBlock& data) +void DetermInvGenerator::performCallback(NodeID proc, Address address) { - Address address = data.getAddress(); assert(proc == m_node); assert(address == m_address); DEBUG_EXPR(TESTER_COMP, LowPrio, proc); DEBUG_EXPR(TESTER_COMP, LowPrio, m_status); DEBUG_EXPR(TESTER_COMP, LowPrio, address); - DEBUG_EXPR(TESTER_COMP, LowPrio, data); if (m_status == DetermInvGeneratorStatus_Load_Pending) { - m_driver.recordLoadLatency(g_eventQueue_ptr->getTime() - m_last_transition); - m_driver.loadCompleted(m_node, data.getAddress()); + m_driver.recordLoadLatency(m_driver.eventQueue->getTime() - m_last_transition); + //NodeID firstByte = data.readByte(); // dummy read + + m_driver.loadCompleted(m_node, address); if (!m_driver.isStoreReady(m_node, m_address)) { // if we don't have to store, we are done for this transaction m_counter++; } - if (m_counter < g_tester_length) { + if (m_counter < m_driver.m_tester_length) { m_status = DetermInvGeneratorStatus_Load_Complete; - m_last_transition = g_eventQueue_ptr->getTime(); - g_eventQueue_ptr->scheduleEvent(this, waitTime()); + m_last_transition = m_driver.eventQueue->getTime(); + m_driver.eventQueue->scheduleEvent(this, waitTime()); } else { m_driver.reportDone(); m_status = DetermInvGeneratorStatus_Done; - m_last_transition = g_eventQueue_ptr->getTime(); + m_last_transition = m_driver.eventQueue->getTime(); } } else if (m_status == DetermInvGeneratorStatus_Store_Pending) { - m_driver.recordStoreLatency(g_eventQueue_ptr->getTime() - m_last_transition); - data.writeByte(m_node); - m_driver.storeCompleted(m_node, data.getAddress()); // advance the store queue + m_driver.recordStoreLatency(m_driver.eventQueue->getTime() - m_last_transition); + //data.writeByte(m_node); + m_driver.storeCompleted(m_node, address); // advance the store queue m_counter++; - if (m_counter < g_tester_length) { + if (m_counter < m_driver.m_tester_length) { m_status = DetermInvGeneratorStatus_Thinking; - m_last_transition = g_eventQueue_ptr->getTime(); - g_eventQueue_ptr->scheduleEvent(this, waitTime()); + m_last_transition = m_driver.eventQueue->getTime(); + m_driver.eventQueue->scheduleEvent(this, waitTime()); } else { m_driver.reportDone(); m_status = DetermInvGeneratorStatus_Done; - m_last_transition = g_eventQueue_ptr->getTime(); + m_last_transition = m_driver.eventQueue->getTime(); } } else { WARN_EXPR(m_status); @@ -150,23 +146,22 @@ void DetermInvGenerator::performCallback(NodeID proc, SubBlock& data) DEBUG_EXPR(TESTER_COMP, LowPrio, proc); DEBUG_EXPR(TESTER_COMP, LowPrio, m_status); DEBUG_EXPR(TESTER_COMP, LowPrio, address); - DEBUG_EXPR(TESTER_COMP, LowPrio, data); } int DetermInvGenerator::thinkTime() const { - return g_think_time; + return m_driver.m_think_time; } int DetermInvGenerator::waitTime() const { - return g_wait_time; + return m_driver.m_wait_time; } int DetermInvGenerator::holdTime() const { - return g_hold_time; + assert(0); } void DetermInvGenerator::pickLoadAddress() @@ -179,35 +174,42 @@ void DetermInvGenerator::pickLoadAddress() void DetermInvGenerator::initiateLoad() { DEBUG_MSG(TESTER_COMP, MedPrio, "initiating Load"); + // sequencer()->makeRequest(CacheMsg(m_address, m_address, CacheRequestType_LD, Address(1), AccessModeType_UserMode, 1, PrefetchBit_No, Address(0), 0 /* only 1 SMT thread */)); + uint8_t * read_data = new uint8_t[64]; - Addr data_addr = m_address.getAddress(); - Request request(0, data_addr, 1, Flags(), 1, 0, 0); - MemCmd::Command command; - command = MemCmd::ReadReq; + char name [] = "Sequencer_"; + char port_name [13]; + sprintf(port_name, "%s%d", name, m_node); - Packet pkt(&request, command, 0); // TODO -- make dest a real NodeID + int64_t request_id = libruby_issue_request(libruby_get_port_by_name(port_name), RubyRequest(m_address.getAddress(), read_data, 64, 0, RubyRequestType_LD, RubyAccessMode_Supervisor)); - sequencer()->makeRequest(&pkt); + //delete [] read_data; + + ASSERT(m_driver.requests.find(request_id) == m_driver.requests.end()); + m_driver.requests.insert(make_pair(request_id, make_pair(m_node, m_address))); } void DetermInvGenerator::initiateStore() { DEBUG_MSG(TESTER_COMP, MedPrio, "initiating Store"); + // sequencer()->makeRequest(CacheMsg(m_address, m_address, CacheRequestType_ST, Address(3), AccessModeType_UserMode, 1, PrefetchBit_No, Address(0), 0 /* only 1 SMT thread */)); + uint8_t *write_data = new uint8_t[64]; + for(int i=0; i < 64; i++) { + write_data[i] = m_node; + } - Addr data_addr = m_address.getAddress(); - Request request(0, data_addr, 1, Flags(), 3, 0, 0); - MemCmd::Command command; - command = MemCmd::WriteReq; + char name [] = "Sequencer_"; + char port_name [13]; + sprintf(port_name, "%s%d", name, m_node); - Packet pkt(&request, command, 0); // TODO -- make dest a real NodeID + int64_t request_id = libruby_issue_request(libruby_get_port_by_name(port_name), RubyRequest(m_address.getAddress(), write_data, 64, 0, RubyRequestType_ST, RubyAccessMode_Supervisor)); - sequencer()->makeRequest(&pkt); -} + //delete [] write_data; + + ASSERT(m_driver.requests.find(request_id) == m_driver.requests.end()); + m_driver.requests.insert(make_pair(request_id, make_pair(m_node, m_address))); -Sequencer* DetermInvGenerator::sequencer() const -{ - return g_system_ptr->getChip(m_node/RubyConfig::numberOfProcsPerChip())->getSequencer(m_node%RubyConfig::numberOfProcsPerChip()); } void DetermInvGenerator::print(ostream& out) const diff --git a/src/mem/ruby/tester/DetermInvGenerator.hh b/src/mem/ruby/tester/DetermInvGenerator.hh index 4f0712fbe..6127c3af4 100644 --- a/src/mem/ruby/tester/DetermInvGenerator.hh +++ b/src/mem/ruby/tester/DetermInvGenerator.hh @@ -41,15 +41,12 @@ #ifndef DETERMINVGENERATOR_H #define DETERMINVGENERATOR_H -#include "mem/ruby/common/Global.hh" +#include "mem/ruby/tester/Global_Tester.hh" #include "mem/ruby/common/Consumer.hh" #include "mem/protocol/DetermInvGeneratorStatus.hh" -#include "mem/ruby/system/NodeID.hh" -#include "mem/ruby/common/Address.hh" +#include "Address_Tester.hh" #include "mem/ruby/tester/SpecifiedGenerator.hh" -class Sequencer; -class SubBlock; class DeterministicDriver; class DetermInvGenerator : public SpecifiedGenerator { @@ -62,7 +59,7 @@ public: // Public Methods void wakeup(); - void performCallback(NodeID proc, SubBlock& data); + void performCallback(NodeID proc, Address address); void print(ostream& out) const; private: @@ -75,8 +72,6 @@ private: void pickLoadAddress(); void pickStoreAddress(); - Sequencer* sequencer() const; - // copy constructor and assignment operator DetermInvGenerator(const DetermInvGenerator& obj); DetermInvGenerator& operator=(const DetermInvGenerator& obj); diff --git a/src/mem/ruby/tester/DetermSeriesGETSGenerator.cc b/src/mem/ruby/tester/DetermSeriesGETSGenerator.cc index 5adc7aa5c..38688f10d 100644 --- a/src/mem/ruby/tester/DetermSeriesGETSGenerator.cc +++ b/src/mem/ruby/tester/DetermSeriesGETSGenerator.cc @@ -34,13 +34,7 @@ #include "mem/ruby/tester/DetermSeriesGETSGenerator.hh" #include "mem/protocol/DetermSeriesGETSGeneratorStatus.hh" -#include "mem/protocol/LockStatus.hh" -#include "mem/ruby/system/Sequencer.hh" -#include "mem/ruby/system/System.hh" -#include "mem/ruby/config/RubyConfig.hh" -#include "mem/ruby/common/SubBlock.hh" #include "mem/ruby/tester/DeterministicDriver.hh" -#include "mem/protocol/Chip.hh" DetermSeriesGETSGenerator::DetermSeriesGETSGenerator(NodeID node, DeterministicDriver& driver) : m_driver(driver) @@ -51,8 +45,9 @@ DetermSeriesGETSGenerator::DetermSeriesGETSGenerator(NodeID node, DeterministicD m_address = Address(9999); // initialize to null value m_counter = 0; + // don't know exactly when this node needs to request so just guess randomly - g_eventQueue_ptr->scheduleEvent(this, 1+(random() % 200)); + m_driver.eventQueue->scheduleEvent(this, 1+(random() % 200)); } DetermSeriesGETSGenerator::~DetermSeriesGETSGenerator() @@ -69,10 +64,10 @@ void DetermSeriesGETSGenerator::wakeup() if (m_driver.isLoadReady(m_node)) { pickAddress(); m_status = DetermSeriesGETSGeneratorStatus_Load_Pending; // Load Pending - m_last_transition = g_eventQueue_ptr->getTime(); + m_last_transition = m_driver.eventQueue->getTime(); initiateLoad(); // SeriesGETS } else { // I'll check again later - g_eventQueue_ptr->scheduleEvent(this, thinkTime()); + m_driver.eventQueue->scheduleEvent(this, thinkTime()); } } else { WARN_EXPR(m_status); @@ -81,32 +76,30 @@ void DetermSeriesGETSGenerator::wakeup() } -void DetermSeriesGETSGenerator::performCallback(NodeID proc, SubBlock& data) +void DetermSeriesGETSGenerator::performCallback(NodeID proc, Address address) { - Address address = data.getAddress(); assert(proc == m_node); assert(address == m_address); DEBUG_EXPR(TESTER_COMP, LowPrio, proc); DEBUG_EXPR(TESTER_COMP, LowPrio, m_status); DEBUG_EXPR(TESTER_COMP, LowPrio, address); - DEBUG_EXPR(TESTER_COMP, LowPrio, data); if (m_status == DetermSeriesGETSGeneratorStatus_Load_Pending) { - m_driver.recordLoadLatency(g_eventQueue_ptr->getTime() - m_last_transition); - data.writeByte(m_node); - m_driver.loadCompleted(m_node, data.getAddress()); // advance the load queue + m_driver.recordLoadLatency(m_driver.eventQueue->getTime() - m_last_transition); + //data.writeByte(m_node); + m_driver.loadCompleted(m_node, address); // advance the load queue m_counter++; // do we still have more requests to complete before the next proc starts? - if (m_counter < g_tester_length*g_NUM_COMPLETIONS_BEFORE_PASS) { + if (m_counter < m_driver.m_tester_length*m_driver.m_numCompletionsPerNode) { m_status = DetermSeriesGETSGeneratorStatus_Thinking; - m_last_transition = g_eventQueue_ptr->getTime(); - g_eventQueue_ptr->scheduleEvent(this, waitTime()); + m_last_transition = m_driver.eventQueue->getTime(); + m_driver.eventQueue->scheduleEvent(this, waitTime()); } else { m_driver.reportDone(); m_status = DetermSeriesGETSGeneratorStatus_Done; - m_last_transition = g_eventQueue_ptr->getTime(); + m_last_transition = m_driver.eventQueue->getTime(); } } else { @@ -117,12 +110,12 @@ void DetermSeriesGETSGenerator::performCallback(NodeID proc, SubBlock& data) int DetermSeriesGETSGenerator::thinkTime() const { - return g_think_time; + return m_driver.m_think_time; } int DetermSeriesGETSGenerator::waitTime() const { - return g_wait_time; + return m_driver.m_wait_time; } void DetermSeriesGETSGenerator::pickAddress() @@ -135,21 +128,20 @@ void DetermSeriesGETSGenerator::pickAddress() void DetermSeriesGETSGenerator::initiateLoad() { DEBUG_MSG(TESTER_COMP, MedPrio, "initiating Load"); + //sequencer()->makeRequest(CacheMsg(m_address, m_address, CacheRequestType_IFETCH, Address(3), AccessModeType_UserMode, 1, PrefetchBit_No, Address(0), 0 /* only 1 SMT thread */)); - Addr data_addr = m_address.getAddress(); - Request request(0, data_addr, 1, Flags(), 3, 0, 0); - MemCmd::Command command; - command = MemCmd::ReadReq; - request.setFlags(Request::INST_FETCH); + uint8_t *read_data = new uint8_t[64]; - Packet pkt(&request, command, 0); // TODO -- make dest a real NodeID + char name [] = "Sequencer_"; + char port_name [13]; + sprintf(port_name, "%s%d", name, m_node); - sequencer()->makeRequest(&pkt); -} + int64_t request_id = libruby_issue_request(libruby_get_port_by_name(port_name), RubyRequest(m_address.getAddress(), read_data, 64, 0, RubyRequestType_LD, RubyAccessMode_Supervisor)); -Sequencer* DetermSeriesGETSGenerator::sequencer() const -{ - return g_system_ptr->getChip(m_node/RubyConfig::numberOfProcsPerChip())->getSequencer(m_node%RubyConfig::numberOfProcsPerChip()); + //delete [] read_data; + + ASSERT(m_driver.requests.find(request_id) == m_driver.requests.end()); + m_driver.requests.insert(make_pair(request_id, make_pair(m_node, m_address))); } void DetermSeriesGETSGenerator::print(ostream& out) const diff --git a/src/mem/ruby/tester/DetermSeriesGETSGenerator.hh b/src/mem/ruby/tester/DetermSeriesGETSGenerator.hh index 1e44dc3bc..225e45a11 100644 --- a/src/mem/ruby/tester/DetermSeriesGETSGenerator.hh +++ b/src/mem/ruby/tester/DetermSeriesGETSGenerator.hh @@ -42,15 +42,12 @@ #ifndef DETERMSERIESGETSGENERATOR_H #define DETERMSERIESGETSGENERATOR_H -#include "mem/ruby/common/Global.hh" +#include "mem/ruby/tester/Global_Tester.hh" #include "mem/ruby/common/Consumer.hh" #include "mem/protocol/DetermSeriesGETSGeneratorStatus.hh" -#include "mem/ruby/system/NodeID.hh" -#include "mem/ruby/common/Address.hh" +#include "Address_Tester.hh" #include "mem/ruby/tester/SpecifiedGenerator.hh" -class Sequencer; -class SubBlock; class DeterministicDriver; class DetermSeriesGETSGenerator : public SpecifiedGenerator { @@ -63,7 +60,7 @@ public: // Public Methods void wakeup(); - void performCallback(NodeID proc, SubBlock& data); + void performCallback(NodeID proc, Address address); void print(ostream& out) const; private: @@ -73,8 +70,6 @@ private: void initiateLoad(); void pickAddress(); - Sequencer* sequencer() const; - // copy constructor and assignment operator DetermSeriesGETSGenerator(const DetermSeriesGETSGenerator& obj); DetermSeriesGETSGenerator& operator=(const DetermSeriesGETSGenerator& obj); diff --git a/src/mem/ruby/tester/DeterministicDriver.cc b/src/mem/ruby/tester/DeterministicDriver.cc index 762672118..54b5f5e0d 100644 --- a/src/mem/ruby/tester/DeterministicDriver.cc +++ b/src/mem/ruby/tester/DeterministicDriver.cc @@ -32,67 +32,79 @@ * */ -#include "mem/ruby/common/Global.hh" -#include "mem/ruby/system/System.hh" +#include "mem/ruby/tester/Global_Tester.hh" #include "mem/ruby/tester/DeterministicDriver.hh" -#include "mem/ruby/eventqueue/RubyEventQueue.hh" -#include "mem/ruby/tester/SpecifiedGenerator.hh" +#include "mem/ruby/tester/EventQueue_Tester.hh" +//#include "DMAGenerator.hh" #include "mem/ruby/tester/DetermGETXGenerator.hh" -#include "mem/ruby/tester/DetermInvGenerator.hh" -#include "mem/ruby/tester/DetermSeriesGETSGenerator.hh" -#include "mem/ruby/common/SubBlock.hh" -#include "mem/protocol/Chip.hh" -#include "mem/packet.hh" -DeterministicDriver::DeterministicDriver(RubySystem* sys_ptr) +#define DATA_BLOCK_BYTES 64 + +DeterministicDriver::DeterministicDriver(string generator_type, int num_completions, int num_procs, Time g_think_time, Time g_wait_time, int g_tester_length) { + eventQueue = new RubyEventQueue; m_finish_time = 0; m_last_issue = -11; m_done_counter = 0; m_loads_completed = 0; m_stores_completed = 0; - m_numCompletionsPerNode = g_NUM_COMPLETIONS_BEFORE_PASS; + m_numCompletionsPerNode = num_completions; + m_num_procs = num_procs; + m_think_time = g_think_time; + m_wait_time = g_wait_time; + m_tester_length = g_tester_length; + - m_last_progress_vector.setSize(RubyConfig::numberOfProcessors()); + m_last_progress_vector.setSize(num_procs); for (int i=0; ischeduleEvent(this, 1); + //m_dma_generator = new DMAGenerator(0, this); } + +void DeterministicDriver::go() +{ + // tick both queues until everyone is done + while (m_done_counter != m_num_procs) { + libruby_tick(1); + eventQueue->triggerEvents(eventQueue->getTime() + 1); + } +} + + DeterministicDriver::~DeterministicDriver() { for (int i=0; iperformCallback(); +//} + +void DeterministicDriver::wakeup() { + assert(0); + // this shouldn't be called as we are not scheduling the driver ever +} + +void DeterministicDriver::hitCallback(int64_t request_id) { - NodeID proc = pkt->req->contextId(); - SubBlock data(Address(pkt->getAddr()), pkt->req->getSize()); - if (pkt->hasData()) { - for (int i = 0; i < pkt->req->getSize(); i++) { - data.setByte(i, *(pkt->getPtr()+i)); - } - } - m_generator_vector[proc]->performCallback(proc, data); - m_last_progress_vector[proc] = g_eventQueue_ptr->getTime(); + ASSERT(requests.find(request_id) != requests.end()); + int proc = requests[request_id].first; + Address address = requests[request_id].second; + + m_generator_vector[proc]->performCallback(proc, address); + + m_last_progress_vector[proc] = eventQueue->getTime(); + + requests.erase(request_id); } bool DeterministicDriver::isStoreReady(NodeID node) @@ -121,6 +142,8 @@ bool DeterministicDriver::isStoreReady(NodeID node) bool DeterministicDriver::isStoreReady(NodeID node, Address addr) { + int addr_number = addr.getAddress()/DATA_BLOCK_BYTES; + return isAddrReady(node, m_store_vector, addr); } @@ -138,25 +161,26 @@ bool DeterministicDriver::isLoadReady(NodeID node, Address addr) bool DeterministicDriver::isAddrReady(NodeID node, Vector addr_vector) { for (int i=0; i= m_numCompletionsPerNode*node) && // is this node next - (g_eventQueue_ptr->getTime() >= m_last_issue + 10)) { // controll rate of requests + (eventQueue->getTime() >= m_last_issue + 10)) { // controll rate of requests return true; } } + return false; } // test for a particular addr bool DeterministicDriver::isAddrReady(NodeID node, Vector addr_vector, Address addr) { - int addr_number = addr.getAddress()/RubyConfig::dataBlockBytes(); + int addr_number = addr.getAddress()/DATA_BLOCK_BYTES; ASSERT ((addr_number >= 0) && (addr_number < addr_vector.size())); - if (((addr_vector[addr_number]+1)%RubyConfig::numberOfProcessors() == node) && + if (((addr_vector[addr_number]+1)%m_num_procs == node) && (m_loads_completed+m_stores_completed >= m_numCompletionsPerNode*node) && // is this node next - (g_eventQueue_ptr->getTime() >= m_last_issue + 10)) { // controll rate of requests + (eventQueue->getTime() >= m_last_issue + 10)) { // controll rate of requests return true; } else { return false; @@ -178,7 +202,7 @@ void DeterministicDriver::storeCompleted(NodeID node, Address addr) void DeterministicDriver::setNextAddr(NodeID node, Address addr, Vector& addr_vector) { // mark the addr vector that this proc was the last to use the particular address - int addr_number = addr.getAddress()/RubyConfig::dataBlockBytes(); + int addr_number = addr.getAddress()/DATA_BLOCK_BYTES; addr_vector[addr_number] = node; } @@ -204,17 +228,16 @@ Address DeterministicDriver::getNextAddr(NodeID node, Vector addr_vector ASSERT(isAddrReady(node, addr_vector)); for (int addr_number=0; addr_number0; addr_number--) { // is this node next in line for the addr - if (((addr_vector[addr_number]+1)%RubyConfig::numberOfProcessors()) == node) { + if ((addr_vector[addr_number] != 1) && ((addr_vector[addr_number]+1)%m_num_procs) == node) { // One addr per cache line - addr.setAddress(addr_number * RubyConfig::dataBlockBytes()); + addr.setAddress(addr_number * DATA_BLOCK_BYTES); } } - m_last_issue = g_eventQueue_ptr->getTime(); + m_last_issue = eventQueue->getTime(); return addr; } @@ -223,9 +246,9 @@ Address DeterministicDriver::getNextAddr(NodeID node, Vector addr_vector void DeterministicDriver::reportDone() { m_done_counter++; - if ((m_done_counter == RubyConfig::numberOfProcessors())) { - //|| (m_done_counter == g_tester_length)) { - m_finish_time = g_eventQueue_ptr->getTime(); + if ((m_done_counter == m_num_procs)) { + m_finish_time = eventQueue->getTime(); + //m_dma_generator->stop(); } } @@ -239,36 +262,6 @@ void DeterministicDriver::recordStoreLatency(Time time) m_store_latency.add(time); } -void DeterministicDriver::wakeup() -{ - // checkForDeadlock(); - if (m_done_counter < RubyConfig::numberOfProcessors()) { - g_eventQueue_ptr->scheduleEvent(this, g_DEADLOCK_THRESHOLD); - } -} - -void DeterministicDriver::checkForDeadlock() -{ - int size = m_last_progress_vector.size(); - Time current_time = g_eventQueue_ptr->getTime(); - for (int processor=0; processor g_DEADLOCK_THRESHOLD) { - WARN_EXPR(processor); -#ifndef NDEBUG - Sequencer* seq_ptr = g_system_ptr->getChip(processor/RubyConfig::numberOfProcsPerChip())->getSequencer(processor%RubyConfig::numberOfProcsPerChip()); -#endif - assert(seq_ptr != NULL); - // if (seq_ptr->isRequestPending()) { - // WARN_EXPR(seq_ptr->pendingAddress()); - // } - WARN_EXPR(current_time); - WARN_EXPR(m_last_progress_vector[processor]); - WARN_EXPR(current_time - m_last_progress_vector[processor]); - ERROR_MSG("Deadlock detected."); - } - } -} - void DeterministicDriver::printStats(ostream& out) const { out << endl; diff --git a/src/mem/ruby/tester/DeterministicDriver.hh b/src/mem/ruby/tester/DeterministicDriver.hh index 710da7922..288ad5a15 100644 --- a/src/mem/ruby/tester/DeterministicDriver.hh +++ b/src/mem/ruby/tester/DeterministicDriver.hh @@ -36,25 +36,35 @@ #ifndef DETERMINISTICDRIVER_H #define DETERMINISTICDRIVER_H - -#include "mem/ruby/common/Global.hh" -#include "mem/ruby/common/Driver.hh" -#include "mem/ruby/common/Histogram.hh" -#include "mem/protocol/CacheRequestType.hh" - -class RubySystem; -class SpecifiedGenerator; -class Packet; - -class DeterministicDriver : public Driver, public Consumer { +#include +#include "mem/ruby/tester/Global_Tester.hh" +#include "mem/ruby/common/Histogram.hh" // includes global, but doesn't use anything, so it should be fine +#include "mem/protocol/CacheRequestType.hh" // includes global, but doesn't use anything, so it should be fine +#include "Address_Tester.hh" // we redefined the address +#include "mem/ruby/tester/DetermGETXGenerator.hh" // this is our file +#include "mem/ruby/tester/DetermSeriesGETSGenerator.hh" // this is our file +#include "mem/ruby/tester/DetermInvGenerator.hh" // this is our file +#include "mem/ruby/libruby.hh" +#include "mem/ruby/tester/Driver_Tester.hh" +#include "mem/ruby/common/Consumer.hh" +#include "mem/ruby/tester/EventQueue_Tester.hh" +#include "mem/protocol/SpecifiedGeneratorType.hh" + +//class DMAGenerator; + +class DeterministicDriver : public Driver_Tester, public Consumer { public: + friend class DetermGETXGenerator; + friend class DetermSeriesGETSGenerator; + friend class DetermInvGenerator; // Constructors - DeterministicDriver(RubySystem* sys_ptr); + DeterministicDriver(string generator_type, int num_completions, int num_procs, Time g_think_time, Time g_wait_time, int g_tester_length); // Destructor ~DeterministicDriver(); // Public Methods + void go(); bool isStoreReady(NodeID node); bool isLoadReady(NodeID node); bool isStoreReady(NodeID node, Address addr); @@ -70,37 +80,47 @@ public: void recordLoadLatency(Time time); void recordStoreLatency(Time time); - void hitCallback(Packet* pkt); +// void dmaHitCallback(); + void hitCallback(int64_t request_id); void wakeup(); void printStats(ostream& out) const; void clearStats() {} void printConfig(ostream& out) const {} void print(ostream& out) const; + // Public copy constructor and assignment operator + DeterministicDriver(const DeterministicDriver& obj); + DeterministicDriver& operator=(const DeterministicDriver& obj); + private: // Private Methods - void checkForDeadlock(); Address getNextAddr(NodeID node, Vector addr_vector); bool isAddrReady(NodeID node, Vector addr_vector); bool isAddrReady(NodeID node, Vector addr_vector, Address addr); void setNextAddr(NodeID node, Address addr, Vector& addr_vector); - // Private copy constructor and assignment operator - DeterministicDriver(const DeterministicDriver& obj); - DeterministicDriver& operator=(const DeterministicDriver& obj); // Data Members (m_ prefix) Vector