From 2f30950143cc70bc42a3c8a4111d7cf8198ec881 Mon Sep 17 00:00:00 2001 From: Nathan Binkert Date: Mon, 11 May 2009 10:38:43 -0700 Subject: ruby: Import ruby and slicc from GEMS We eventually plan to replace the m5 cache hierarchy with the GEMS hierarchy, but for now we will make both live alongside eachother. --- src/mem/ruby/tester/BarrierGenerator.cc | 333 ++++++++++++ src/mem/ruby/tester/BarrierGenerator.hh | 138 +++++ src/mem/ruby/tester/Check.cc | 251 +++++++++ src/mem/ruby/tester/Check.hh | 107 ++++ src/mem/ruby/tester/CheckTable.cc | 128 +++++ src/mem/ruby/tester/CheckTable.hh | 93 ++++ src/mem/ruby/tester/DetermGETXGenerator.cc | 151 ++++++ src/mem/ruby/tester/DetermGETXGenerator.hh | 104 ++++ src/mem/ruby/tester/DetermInvGenerator.cc | 202 +++++++ src/mem/ruby/tester/DetermInvGenerator.hh | 109 ++++ src/mem/ruby/tester/DetermSeriesGETSGenerator.cc | 149 ++++++ src/mem/ruby/tester/DetermSeriesGETSGenerator.hh | 106 ++++ src/mem/ruby/tester/DeterministicDriver.cc | 282 ++++++++++ src/mem/ruby/tester/DeterministicDriver.hh | 125 +++++ src/mem/ruby/tester/Instruction.cc | 51 ++ src/mem/ruby/tester/Instruction.hh | 57 ++ src/mem/ruby/tester/RaceyDriver.cc | 139 +++++ src/mem/ruby/tester/RaceyDriver.hh | 112 ++++ src/mem/ruby/tester/RequestGenerator.cc | 196 +++++++ src/mem/ruby/tester/RequestGenerator.hh | 102 ++++ src/mem/ruby/tester/SpecifiedGenerator.cc | 48 ++ src/mem/ruby/tester/SpecifiedGenerator.hh | 69 +++ src/mem/ruby/tester/SyntheticDriver.cc | 296 +++++++++++ src/mem/ruby/tester/SyntheticDriver.hh | 118 +++++ src/mem/ruby/tester/Tester.cc | 116 +++++ src/mem/ruby/tester/Tester.hh | 93 ++++ src/mem/ruby/tester/XactAbortRequestGenerator.cc | 403 ++++++++++++++ src/mem/ruby/tester/XactAbortRequestGenerator.hh | 122 +++++ src/mem/ruby/tester/XactRequestGenerator.cc | 637 +++++++++++++++++++++++ src/mem/ruby/tester/XactRequestGenerator.hh | 134 +++++ src/mem/ruby/tester/main.cc | 51 ++ src/mem/ruby/tester/main.hh | 42 ++ src/mem/ruby/tester/test_framework.cc | 431 +++++++++++++++ src/mem/ruby/tester/test_framework.hh | 46 ++ 34 files changed, 5541 insertions(+) create mode 100644 src/mem/ruby/tester/BarrierGenerator.cc create mode 100644 src/mem/ruby/tester/BarrierGenerator.hh create mode 100644 src/mem/ruby/tester/Check.cc create mode 100644 src/mem/ruby/tester/Check.hh create mode 100644 src/mem/ruby/tester/CheckTable.cc create mode 100644 src/mem/ruby/tester/CheckTable.hh create mode 100644 src/mem/ruby/tester/DetermGETXGenerator.cc create mode 100644 src/mem/ruby/tester/DetermGETXGenerator.hh create mode 100644 src/mem/ruby/tester/DetermInvGenerator.cc create mode 100644 src/mem/ruby/tester/DetermInvGenerator.hh create mode 100644 src/mem/ruby/tester/DetermSeriesGETSGenerator.cc create mode 100644 src/mem/ruby/tester/DetermSeriesGETSGenerator.hh create mode 100644 src/mem/ruby/tester/DeterministicDriver.cc create mode 100644 src/mem/ruby/tester/DeterministicDriver.hh create mode 100644 src/mem/ruby/tester/Instruction.cc create mode 100644 src/mem/ruby/tester/Instruction.hh create mode 100644 src/mem/ruby/tester/RaceyDriver.cc create mode 100644 src/mem/ruby/tester/RaceyDriver.hh create mode 100644 src/mem/ruby/tester/RequestGenerator.cc create mode 100644 src/mem/ruby/tester/RequestGenerator.hh create mode 100644 src/mem/ruby/tester/SpecifiedGenerator.cc create mode 100644 src/mem/ruby/tester/SpecifiedGenerator.hh create mode 100644 src/mem/ruby/tester/SyntheticDriver.cc create mode 100644 src/mem/ruby/tester/SyntheticDriver.hh create mode 100644 src/mem/ruby/tester/Tester.cc create mode 100644 src/mem/ruby/tester/Tester.hh create mode 100644 src/mem/ruby/tester/XactAbortRequestGenerator.cc create mode 100644 src/mem/ruby/tester/XactAbortRequestGenerator.hh create mode 100644 src/mem/ruby/tester/XactRequestGenerator.cc create mode 100644 src/mem/ruby/tester/XactRequestGenerator.hh create mode 100644 src/mem/ruby/tester/main.cc create mode 100644 src/mem/ruby/tester/main.hh create mode 100644 src/mem/ruby/tester/test_framework.cc create mode 100644 src/mem/ruby/tester/test_framework.hh (limited to 'src/mem/ruby/tester') diff --git a/src/mem/ruby/tester/BarrierGenerator.cc b/src/mem/ruby/tester/BarrierGenerator.cc new file mode 100644 index 000000000..79b9c6d2b --- /dev/null +++ b/src/mem/ruby/tester/BarrierGenerator.cc @@ -0,0 +1,333 @@ + +/* + * 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 "BarrierGenerator.hh" +#include "Sequencer.hh" +#include "System.hh" +#include "RubyConfig.hh" +#include "SubBlock.hh" +#include "SyntheticDriver.hh" +#include "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 new file mode 100644 index 000000000..1b16755a5 --- /dev/null +++ b/src/mem/ruby/tester/BarrierGenerator.hh @@ -0,0 +1,138 @@ + +/* + * 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 "Global.hh" +#include "Consumer.hh" +#include "NodeID.hh" +#include "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 new file mode 100644 index 000000000..3e2649709 --- /dev/null +++ b/src/mem/ruby/tester/Check.cc @@ -0,0 +1,251 @@ + +/* + * 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 "Check.hh" +#include "Sequencer.hh" +#include "System.hh" +#include "SubBlock.hh" +#include "Chip.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; + } + assert(targetSequencer_ptr != NULL); + CacheMsg request(m_address, m_address, type, m_pc, m_access_mode, 0, PrefetchBit_Yes, 0, Address(0), 0 /* only 1 SMT thread */, 0, false); + if (targetSequencer_ptr->isReady(request)) { + targetSequencer_ptr->makeRequest(request); + } +} + +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; + } + + CacheMsg request(Address(m_address.getAddress()+m_store_count), Address(m_address.getAddress()+m_store_count), type, m_pc, m_access_mode, 1, PrefetchBit_No, 0, Address(0), 0 /* only 1 SMT thread */, 0, false); + Sequencer* sequencer_ptr = initiatingSequencer(); + if (sequencer_ptr->isReady(request) == 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(request); + } + 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; + } + + CacheMsg request(m_address, m_address, type, m_pc, m_access_mode, CHECK_SIZE, PrefetchBit_No, 0, Address(0), 0 /* only 1 SMT thread */, 0, false); + Sequencer* sequencer_ptr = initiatingSequencer(); + if (sequencer_ptr->isReady(request) == 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(request); + } + 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 new file mode 100644 index 000000000..31959262d --- /dev/null +++ b/src/mem/ruby/tester/Check.hh @@ -0,0 +1,107 @@ + +/* + * 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 "Global.hh" +#include "Address.hh" +#include "NodeID.hh" +#include "TesterStatus.hh" +#include "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 new file mode 100644 index 000000000..4a162f5bc --- /dev/null +++ b/src/mem/ruby/tester/CheckTable.hh @@ -0,0 +1,93 @@ + +/* + * 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 "Global.hh" +#include "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 new file mode 100644 index 000000000..1caebbdab --- /dev/null +++ b/src/mem/ruby/tester/DetermGETXGenerator.cc @@ -0,0 +1,151 @@ + +/* + * 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$ + * + */ + +// This Deterministic Generator generates GETX requests for all nodes in the system +// The GETX requests are generated one at a time in round-robin fashion 0...1...2...etc. + +#include "DetermGETXGenerator.hh" +#include "DetermGETXGeneratorStatus.hh" +#include "LockStatus.hh" +#include "Sequencer.hh" +#include "System.hh" +#include "RubyConfig.hh" +#include "SubBlock.hh" +#include "DeterministicDriver.hh" +#include "Chip.hh" + +DetermGETXGenerator::DetermGETXGenerator(NodeID node, DeterministicDriver& driver) : + m_driver(driver) +{ + m_status = DetermGETXGeneratorStatus_Thinking; + m_last_transition = 0; + m_node = node; + 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)); +} + +DetermGETXGenerator::~DetermGETXGenerator() +{ +} + +void DetermGETXGenerator::wakeup() +{ + DEBUG_EXPR(TESTER_COMP, MedPrio, m_node); + DEBUG_EXPR(TESTER_COMP, MedPrio, m_status); + + // determine if this node is next for the GETX round robin request + if (m_status == DetermGETXGeneratorStatus_Thinking) { + if (m_driver.isStoreReady(m_node)) { + pickAddress(); + m_status = DetermGETXGeneratorStatus_Store_Pending; // Store Pending + m_last_transition = g_eventQueue_ptr->getTime(); + initiateStore(); // GETX + } else { // I'll check again later + g_eventQueue_ptr->scheduleEvent(this, thinkTime()); + } + } else { + WARN_EXPR(m_status); + ERROR_MSG("Invalid status"); + } + +} + +void DetermGETXGenerator::performCallback(NodeID proc, SubBlock& data) +{ + 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 + + m_counter++; + if (m_counter < g_tester_length) { + m_status = DetermGETXGeneratorStatus_Thinking; + m_last_transition = g_eventQueue_ptr->getTime(); + g_eventQueue_ptr->scheduleEvent(this, waitTime()); + } else { + m_driver.reportDone(); + m_status = DetermGETXGeneratorStatus_Done; + m_last_transition = g_eventQueue_ptr->getTime(); + } + + } else { + WARN_EXPR(m_status); + ERROR_MSG("Invalid status"); + } +} + +int DetermGETXGenerator::thinkTime() const +{ + return g_think_time; +} + +int DetermGETXGenerator::waitTime() const +{ + return g_wait_time; +} + +void DetermGETXGenerator::pickAddress() +{ + assert(m_status == DetermGETXGeneratorStatus_Thinking); + + m_address = m_driver.getNextStoreAddr(m_node); +} + +void DetermGETXGenerator::initiateStore() +{ + DEBUG_MSG(TESTER_COMP, MedPrio, "initiating Store"); + sequencer()->makeRequest(CacheMsg(m_address, m_address, CacheRequestType_ST, Address(3), AccessModeType_UserMode, 1, PrefetchBit_No, 0, Address(0), 0 /* only 1 SMT thread */, 0, false)); +} + +Sequencer* DetermGETXGenerator::sequencer() const +{ + return g_system_ptr->getChip(m_node/RubyConfig::numberOfProcsPerChip())->getSequencer(m_node%RubyConfig::numberOfProcsPerChip()); +} + +void DetermGETXGenerator::print(ostream& out) const +{ +} + diff --git a/src/mem/ruby/tester/DetermGETXGenerator.hh b/src/mem/ruby/tester/DetermGETXGenerator.hh new file mode 100644 index 000000000..eff1eb6b3 --- /dev/null +++ b/src/mem/ruby/tester/DetermGETXGenerator.hh @@ -0,0 +1,104 @@ + +/* + * 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: + * + */ + +// This Deterministic Generator generates GETX requests for all nodes in the system +// The GETX requests are generated one at a time in round-robin fashion 0...1...2...etc. + +#ifndef DETERMGETXGENERATOR_H +#define DETERMGETXGENERATOR_H + +#include "Global.hh" +#include "Consumer.hh" +#include "DetermGETXGeneratorStatus.hh" +#include "NodeID.hh" +#include "Address.hh" +#include "SpecifiedGenerator.hh" + +class Sequencer; +class SubBlock; +class DeterministicDriver; + +class DetermGETXGenerator : public SpecifiedGenerator { +public: + // Constructors + DetermGETXGenerator(NodeID node, DeterministicDriver& driver); + + // Destructor + ~DetermGETXGenerator(); + + // Public Methods + void wakeup(); + void performCallback(NodeID proc, SubBlock& data); + + void print(ostream& out) const; +private: + // Private Methods + int thinkTime() const; + int waitTime() const; + void initiateStore(); + void pickAddress(); + + Sequencer* sequencer() const; + + // copy constructor and assignment operator + DetermGETXGenerator(const DetermGETXGenerator& obj); + DetermGETXGenerator& operator=(const DetermGETXGenerator& obj); + + // Data Members (m_ prefix) + DetermGETXGeneratorStatus m_status; + int m_counter; + Address m_address; + NodeID m_node; + DeterministicDriver& m_driver; + Time m_last_transition; +}; + +// Output operator declaration +ostream& operator<<(ostream& out, const DetermGETXGenerator& obj); + +// ******************* Definitions ******************* + +// Output operator definition +extern inline +ostream& operator<<(ostream& out, const DetermGETXGenerator& obj) +{ + obj.print(out); + out << flush; + return out; +} + +#endif //DETERMGETXGENERATOR_H + diff --git a/src/mem/ruby/tester/DetermInvGenerator.cc b/src/mem/ruby/tester/DetermInvGenerator.cc new file mode 100644 index 000000000..020c2fe96 --- /dev/null +++ b/src/mem/ruby/tester/DetermInvGenerator.cc @@ -0,0 +1,202 @@ + +/* + * 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$ + * + */ + +// This Deterministic Generator generates GETS request for all nodes in the system +// then Invalidates them with a GETX. The GETS and GETX request are generated one +// at a time in round-robin fashion 0...1...2...etc. + +#include "DetermInvGenerator.hh" +#include "DetermInvGeneratorStatus.hh" +#include "LockStatus.hh" +#include "Sequencer.hh" +#include "System.hh" +#include "RubyConfig.hh" +#include "SubBlock.hh" +#include "DeterministicDriver.hh" +#include "Chip.hh" + +DetermInvGenerator::DetermInvGenerator(NodeID node, DeterministicDriver& driver) : + m_driver(driver) +{ + m_status = DetermInvGeneratorStatus_Thinking; + m_last_transition = 0; + 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)); +} + +DetermInvGenerator::~DetermInvGenerator() +{ +} + +void DetermInvGenerator::wakeup() +{ + DEBUG_EXPR(TESTER_COMP, MedPrio, m_node); + DEBUG_EXPR(TESTER_COMP, MedPrio, m_status); + + // determine if this node is next for the load round robin request + if (m_status == DetermInvGeneratorStatus_Thinking) { + // is a load ready and waiting and are my transactions insync with global transactions + 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(); + initiateLoad(); // GETS + } else { // I'll check again later + g_eventQueue_ptr->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(); + initiateStore(); // GETX + } else { // I'm next, I just have to wait for all loads to complete + g_eventQueue_ptr->scheduleEvent(this, thinkTime()); + } + } else { // I'm not next to store, go back to thinking + m_status = DetermInvGeneratorStatus_Thinking; + g_eventQueue_ptr->scheduleEvent(this, thinkTime()); + } + } else { + WARN_EXPR(m_status); + ERROR_MSG("Invalid status"); + } + +} + +void DetermInvGenerator::performCallback(NodeID proc, SubBlock& data) +{ + 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); + NodeID firstByte = data.readByte(); // dummy read + + m_driver.loadCompleted(m_node, data.getAddress()); + + 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) { + m_status = DetermInvGeneratorStatus_Load_Complete; + m_last_transition = g_eventQueue_ptr->getTime(); + g_eventQueue_ptr->scheduleEvent(this, waitTime()); + } else { + m_driver.reportDone(); + m_status = DetermInvGeneratorStatus_Done; + m_last_transition = g_eventQueue_ptr->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_counter++; + if (m_counter < g_tester_length) { + m_status = DetermInvGeneratorStatus_Thinking; + m_last_transition = g_eventQueue_ptr->getTime(); + g_eventQueue_ptr->scheduleEvent(this, waitTime()); + } else { + m_driver.reportDone(); + m_status = DetermInvGeneratorStatus_Done; + m_last_transition = g_eventQueue_ptr->getTime(); + } + } else { + WARN_EXPR(m_status); + ERROR_MSG("Invalid status"); + } + + 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; +} + +int DetermInvGenerator::waitTime() const +{ + return g_wait_time; +} + +int DetermInvGenerator::holdTime() const +{ + return g_hold_time; +} + +void DetermInvGenerator::pickLoadAddress() +{ + assert(m_status == DetermInvGeneratorStatus_Thinking); + + m_address = m_driver.getNextLoadAddr(m_node); +} + +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, 0, Address(0), 0 /* only 1 SMT thread */, 0, false)); +} + +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, 0, Address(0), 0 /* only 1 SMT thread */, 0, false)); +} + +Sequencer* DetermInvGenerator::sequencer() const +{ + return g_system_ptr->getChip(m_node/RubyConfig::numberOfProcsPerChip())->getSequencer(m_node%RubyConfig::numberOfProcsPerChip()); +} + +void DetermInvGenerator::print(ostream& out) const +{ + out << "[DetermInvGenerator]" << endl; +} + diff --git a/src/mem/ruby/tester/DetermInvGenerator.hh b/src/mem/ruby/tester/DetermInvGenerator.hh new file mode 100644 index 000000000..a72895f3f --- /dev/null +++ b/src/mem/ruby/tester/DetermInvGenerator.hh @@ -0,0 +1,109 @@ + +/* + * 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: + * + */ + +// This Deterministic Generator generates GETS request for all nodes in the system +// then Invalidates them with a GETX. The GETS and GETX request are generated one +// at a time in round-robin fashion 0...1...2...etc. + +#ifndef DETERMINVGENERATOR_H +#define DETERMINVGENERATOR_H + +#include "Global.hh" +#include "Consumer.hh" +#include "DetermInvGeneratorStatus.hh" +#include "NodeID.hh" +#include "Address.hh" +#include "SpecifiedGenerator.hh" + +class Sequencer; +class SubBlock; +class DeterministicDriver; + +class DetermInvGenerator : public SpecifiedGenerator { +public: + // Constructors + DetermInvGenerator(NodeID node, DeterministicDriver& driver); + + // Destructor + ~DetermInvGenerator(); + + // Public Methods + void wakeup(); + void performCallback(NodeID proc, SubBlock& data); + + void print(ostream& out) const; +private: + // Private Methods + int thinkTime() const; + int waitTime() const; + int holdTime() const; + void initiateLoad(); + void initiateStore(); + void pickLoadAddress(); + void pickStoreAddress(); + + Sequencer* sequencer() const; + + // copy constructor and assignment operator + DetermInvGenerator(const DetermInvGenerator& obj); + DetermInvGenerator& operator=(const DetermInvGenerator& obj); + + // Data Members (m_ prefix) + DetermInvGeneratorStatus m_status; + int m_counter; + Address m_address; + NodeID m_node; + DeterministicDriver& m_driver; + Time m_last_transition; + +}; + +// Output operator declaration +ostream& operator<<(ostream& out, const DetermInvGenerator& obj); + +// ******************* Definitions ******************* + +// Output operator definition +extern inline +ostream& operator<<(ostream& out, const DetermInvGenerator& obj) +{ + obj.print(out); + out << flush; + return out; +} + +#endif //DETERMINVGENERATOR_H + diff --git a/src/mem/ruby/tester/DetermSeriesGETSGenerator.cc b/src/mem/ruby/tester/DetermSeriesGETSGenerator.cc new file mode 100644 index 000000000..815919559 --- /dev/null +++ b/src/mem/ruby/tester/DetermSeriesGETSGenerator.cc @@ -0,0 +1,149 @@ + +/* + * 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 "DetermSeriesGETSGenerator.hh" +#include "DetermSeriesGETSGeneratorStatus.hh" +#include "LockStatus.hh" +#include "Sequencer.hh" +#include "System.hh" +#include "RubyConfig.hh" +#include "SubBlock.hh" +#include "DeterministicDriver.hh" +#include "Chip.hh" + +DetermSeriesGETSGenerator::DetermSeriesGETSGenerator(NodeID node, DeterministicDriver& driver) : + m_driver(driver) +{ + m_status = DetermSeriesGETSGeneratorStatus_Thinking; + m_last_transition = 0; + m_node = node; + 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)); +} + +DetermSeriesGETSGenerator::~DetermSeriesGETSGenerator() +{ +} + +void DetermSeriesGETSGenerator::wakeup() +{ + DEBUG_EXPR(TESTER_COMP, MedPrio, m_node); + DEBUG_EXPR(TESTER_COMP, MedPrio, m_status); + + // determine if this node is next for the SeriesGETS round robin request + if (m_status == DetermSeriesGETSGeneratorStatus_Thinking) { + if (m_driver.isLoadReady(m_node)) { + pickAddress(); + m_status = DetermSeriesGETSGeneratorStatus_Load_Pending; // Load Pending + m_last_transition = g_eventQueue_ptr->getTime(); + initiateLoad(); // SeriesGETS + } else { // I'll check again later + g_eventQueue_ptr->scheduleEvent(this, thinkTime()); + } + } else { + WARN_EXPR(m_status); + ERROR_MSG("Invalid status"); + } + +} + +void DetermSeriesGETSGenerator::performCallback(NodeID proc, SubBlock& data) +{ + 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_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) { + m_status = DetermSeriesGETSGeneratorStatus_Thinking; + m_last_transition = g_eventQueue_ptr->getTime(); + g_eventQueue_ptr->scheduleEvent(this, waitTime()); + } else { + m_driver.reportDone(); + m_status = DetermSeriesGETSGeneratorStatus_Done; + m_last_transition = g_eventQueue_ptr->getTime(); + } + + } else { + WARN_EXPR(m_status); + ERROR_MSG("Invalid status"); + } +} + +int DetermSeriesGETSGenerator::thinkTime() const +{ + return g_think_time; +} + +int DetermSeriesGETSGenerator::waitTime() const +{ + return g_wait_time; +} + +void DetermSeriesGETSGenerator::pickAddress() +{ + assert(m_status == DetermSeriesGETSGeneratorStatus_Thinking); + + m_address = m_driver.getNextLoadAddr(m_node); +} + +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, 0, Address(0), 0 /* only 1 SMT thread */, 0, false)); +} + +Sequencer* DetermSeriesGETSGenerator::sequencer() const +{ + return g_system_ptr->getChip(m_node/RubyConfig::numberOfProcsPerChip())->getSequencer(m_node%RubyConfig::numberOfProcsPerChip()); +} + +void DetermSeriesGETSGenerator::print(ostream& out) const +{ +} + diff --git a/src/mem/ruby/tester/DetermSeriesGETSGenerator.hh b/src/mem/ruby/tester/DetermSeriesGETSGenerator.hh new file mode 100644 index 000000000..25d4886a0 --- /dev/null +++ b/src/mem/ruby/tester/DetermSeriesGETSGenerator.hh @@ -0,0 +1,106 @@ + +/* + * 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: + * + */ + +// This Deterministic Generator generates a series of GETS requests for a given node. +// Sequentially goes through all nodes in the system +// This generator is used to tune the HW prefetcher +// The GETS requests are generated one at a time in round-robin fashion 0...1...2...etc. + +#ifndef DETERMSERIESGETSGENERATOR_H +#define DETERMSERIESGETSGENERATOR_H + +#include "Global.hh" +#include "Consumer.hh" +#include "DetermSeriesGETSGeneratorStatus.hh" +#include "NodeID.hh" +#include "Address.hh" +#include "SpecifiedGenerator.hh" + +class Sequencer; +class SubBlock; +class DeterministicDriver; + +class DetermSeriesGETSGenerator : public SpecifiedGenerator { +public: + // Constructors + DetermSeriesGETSGenerator(NodeID node, DeterministicDriver& driver); + + // Destructor + ~DetermSeriesGETSGenerator(); + + // Public Methods + void wakeup(); + void performCallback(NodeID proc, SubBlock& data); + + void print(ostream& out) const; +private: + // Private Methods + int thinkTime() const; + int waitTime() const; + void initiateLoad(); + void pickAddress(); + + Sequencer* sequencer() const; + + // copy constructor and assignment operator + DetermSeriesGETSGenerator(const DetermSeriesGETSGenerator& obj); + DetermSeriesGETSGenerator& operator=(const DetermSeriesGETSGenerator& obj); + + // Data Members (m_ prefix) + DetermSeriesGETSGeneratorStatus m_status; + int m_counter; + Address m_address; + NodeID m_node; + DeterministicDriver& m_driver; + Time m_last_transition; +}; + +// Output operator declaration +ostream& operator<<(ostream& out, const DetermSeriesGETSGenerator& obj); + +// ******************* Definitions ******************* + +// Output operator definition +extern inline +ostream& operator<<(ostream& out, const DetermSeriesGETSGenerator& obj) +{ + obj.print(out); + out << flush; + return out; +} + +#endif //DETERMSeriesGETSGENERATOR_H + diff --git a/src/mem/ruby/tester/DeterministicDriver.cc b/src/mem/ruby/tester/DeterministicDriver.cc new file mode 100644 index 000000000..dd0507201 --- /dev/null +++ b/src/mem/ruby/tester/DeterministicDriver.cc @@ -0,0 +1,282 @@ + +/* + * 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 "Global.hh" +#include "System.hh" +#include "DeterministicDriver.hh" +#include "EventQueue.hh" +#include "SpecifiedGenerator.hh" +#include "DetermGETXGenerator.hh" +#include "DetermInvGenerator.hh" +#include "DetermSeriesGETSGenerator.hh" +#include "SubBlock.hh" +#include "Chip.hh" + +DeterministicDriver::DeterministicDriver(System* sys_ptr) +{ + if (g_SIMICS) { + ERROR_MSG("g_SIMICS should not be defined."); + } + + 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_last_progress_vector.setSize(RubyConfig::numberOfProcessors()); + for (int i=0; ischeduleEvent(this, 1); +} + +DeterministicDriver::~DeterministicDriver() +{ + for (int i=0; iperformCallback(proc, data); + + // Mark that we made progress + m_last_progress_vector[proc] = g_eventQueue_ptr->getTime(); +} + +bool DeterministicDriver::isStoreReady(NodeID node) +{ + return isAddrReady(node, m_store_vector); +} + +bool DeterministicDriver::isStoreReady(NodeID node, Address addr) +{ + return isAddrReady(node, m_store_vector, addr); +} + +bool DeterministicDriver::isLoadReady(NodeID node) +{ + return isAddrReady(node, m_load_vector); +} + +bool DeterministicDriver::isLoadReady(NodeID node, Address addr) +{ + return isAddrReady(node, m_load_vector, addr); +} + +// searches for any address in the addr_vector +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 + 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(); + + ASSERT ((addr_number >= 0) && (addr_number < addr_vector.size())); + + if (((addr_vector[addr_number]+1)%RubyConfig::numberOfProcessors() == 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 + return true; + } else { + return false; + } +} + +void DeterministicDriver::loadCompleted(NodeID node, Address addr) +{ + m_loads_completed++; + setNextAddr(node, addr, m_load_vector); +} + +void DeterministicDriver::storeCompleted(NodeID node, Address addr) +{ + m_stores_completed++; + setNextAddr(node, addr, m_store_vector); +} + +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(); + addr_vector[addr_number] = node; +} + +Address DeterministicDriver::getNextLoadAddr(NodeID node) +{ + return getNextAddr(node, m_load_vector); +} + +Address DeterministicDriver::getNextStoreAddr(NodeID node) +{ + return getNextAddr(node, m_store_vector); +} + +Address DeterministicDriver::getNextAddr(NodeID node, Vector addr_vector) +{ + + // This method deterministically picks the next addr the node should acquirer + // The addrs cycle through according to NodeID 0->1->...->lastID->0... + + Address addr; + + // should only be called if we know a addr is ready for the node + 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) { + + // One addr per cache line + addr.setAddress(addr_number * RubyConfig::dataBlockBytes()); + } + } + + m_last_issue = g_eventQueue_ptr->getTime(); + + return addr; +} + + +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(); + } +} + +void DeterministicDriver::recordLoadLatency(Time time) +{ + m_load_latency.add(time); +} + +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); + Sequencer* seq_ptr = g_system_ptr->getChip(processor/RubyConfig::numberOfProcsPerChip())->getSequencer(processor%RubyConfig::numberOfProcsPerChip()); + 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; + out << "DeterministicDriver Stats" << endl; + out << "---------------------" << endl; + + out << "finish_time: " << m_finish_time << endl; + out << "load_latency: " << m_load_latency << endl; + out << "store_latency: " << m_store_latency << endl; +} + +void DeterministicDriver::print(ostream& out) const +{ +} diff --git a/src/mem/ruby/tester/DeterministicDriver.hh b/src/mem/ruby/tester/DeterministicDriver.hh new file mode 100644 index 000000000..3d0bae73d --- /dev/null +++ b/src/mem/ruby/tester/DeterministicDriver.hh @@ -0,0 +1,125 @@ + +/* + * 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 DETERMINISTICDRIVER_H +#define DETERMINISTICDRIVER_H + +#include "Global.hh" +#include "Driver.hh" +#include "Histogram.hh" +#include "CacheRequestType.hh" + +class System; +class SpecifiedGenerator; + +class DeterministicDriver : public Driver, public Consumer { +public: + // Constructors + DeterministicDriver(System* sys_ptr); + + // Destructor + ~DeterministicDriver(); + + // Public Methods + bool isStoreReady(NodeID node); + bool isLoadReady(NodeID node); + bool isStoreReady(NodeID node, Address addr); + bool isLoadReady(NodeID node, Address addr); + void loadCompleted(NodeID node, Address addr); + void storeCompleted(NodeID node, Address addr); + Address getNextLoadAddr(NodeID node); + Address getNextStoreAddr(NodeID node); + int getLoadsCompleted() { return m_loads_completed; } + int getStoresCompleted() { return m_stores_completed; } + + void reportDone(); + void recordLoadLatency(Time time); + void recordStoreLatency(Time time); + + void hitCallback(NodeID proc, SubBlock& data, CacheRequestType type, int thread); + void wakeup(); + void printStats(ostream& out) const; + void clearStats() {} + void printConfig(ostream& out) const {} + + void print(ostream& out) const; +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