summaryrefslogtreecommitdiff
path: root/src/mem/ruby/tester
diff options
context:
space:
mode:
Diffstat (limited to 'src/mem/ruby/tester')
-rw-r--r--src/mem/ruby/tester/BarrierGenerator.cc333
-rw-r--r--src/mem/ruby/tester/BarrierGenerator.hh138
-rw-r--r--src/mem/ruby/tester/Check.cc310
-rw-r--r--src/mem/ruby/tester/Check.hh107
-rw-r--r--src/mem/ruby/tester/CheckTable.cc128
-rw-r--r--src/mem/ruby/tester/CheckTable.hh93
-rw-r--r--src/mem/ruby/tester/DetermGETXGenerator.cc160
-rw-r--r--src/mem/ruby/tester/DetermGETXGenerator.hh104
-rw-r--r--src/mem/ruby/tester/DetermInvGenerator.cc217
-rw-r--r--src/mem/ruby/tester/DetermInvGenerator.hh109
-rw-r--r--src/mem/ruby/tester/DetermSeriesGETSGenerator.cc158
-rw-r--r--src/mem/ruby/tester/DetermSeriesGETSGenerator.hh106
-rw-r--r--src/mem/ruby/tester/DeterministicDriver.cc285
-rw-r--r--src/mem/ruby/tester/DeterministicDriver.hh126
-rw-r--r--src/mem/ruby/tester/Instruction.cc51
-rw-r--r--src/mem/ruby/tester/Instruction.hh57
-rw-r--r--src/mem/ruby/tester/RaceyDriver.cc135
-rw-r--r--src/mem/ruby/tester/RaceyDriver.hh112
-rw-r--r--src/mem/ruby/tester/RequestGenerator.cc220
-rw-r--r--src/mem/ruby/tester/RequestGenerator.hh102
-rw-r--r--src/mem/ruby/tester/SConscript46
-rw-r--r--src/mem/ruby/tester/SpecifiedGenerator.cc48
-rw-r--r--src/mem/ruby/tester/SpecifiedGenerator.hh69
-rw-r--r--src/mem/ruby/tester/SyntheticDriver.cc286
-rw-r--r--src/mem/ruby/tester/SyntheticDriver.hh118
-rw-r--r--src/mem/ruby/tester/Tester.cc112
-rw-r--r--src/mem/ruby/tester/Tester.hh93
-rw-r--r--src/mem/ruby/tester/main.cc48
-rw-r--r--src/mem/ruby/tester/main.hh35
-rw-r--r--src/mem/ruby/tester/test_framework.cc426
-rw-r--r--src/mem/ruby/tester/test_framework.hh46
31 files changed, 4378 insertions, 0 deletions
diff --git a/src/mem/ruby/tester/BarrierGenerator.cc b/src/mem/ruby/tester/BarrierGenerator.cc
new file mode 100644
index 000000000..9dbcf39fd
--- /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 "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
new file mode 100644
index 000000000..e0fa497da
--- /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 "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
new file mode 100644
index 000000000..7896b572a
--- /dev/null
+++ b/src/mem/ruby/tester/Check.cc
@@ -0,0 +1,310 @@
+
+/*
+ * 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<unsigned int>(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<unsigned int>(), 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<unsigned int>(), 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_number<CHECK_SIZE; byte_number++) {
+ if (uint8(m_value+byte_number) != data.getByte(byte_number) && (DATA_BLOCK == true)) {
+ WARN_EXPR(proc);
+ WARN_EXPR(address);
+ WARN_EXPR(data);
+ WARN_EXPR(byte_number);
+ WARN_EXPR((int)m_value+byte_number);
+ WARN_EXPR((int)data.getByte(byte_number));
+ WARN_EXPR(*this);
+ WARN_EXPR(g_eventQueue_ptr->getTime());
+ 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..8f08b3f40
--- /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 "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<<CHECK_SIZE_BITS);
+
+class Check {
+public:
+ // Constructors
+ Check(const Address& address, const Address& pc);
+
+ // Default Destructor
+ //~Check();
+
+ // Public Methods
+
+ void initiate(); // Does Action or Check or nether
+ void performCallback(NodeID proc, SubBlock& data);
+ const Address& getAddress() { return m_address; }
+ void changeAddress(const Address& address);
+
+ void print(ostream& out) const;
+private:
+ // Private Methods
+ void initiatePrefetch(Sequencer* targetSequencer_ptr);
+ void initiatePrefetch();
+ void initiateAction();
+ void initiateCheck();
+
+ Sequencer* initiatingSequencer() const;
+
+ void pickValue();
+ void pickInitiatingNode();
+
+ // Using default copy constructor and assignment operator
+ // Check(const Check& obj);
+ // Check& operator=(const Check& obj);
+
+ // Data Members (m_ prefix)
+ TesterStatus m_status;
+ uint8 m_value;
+ int m_store_count;
+ NodeID m_initiatingNode;
+ Address m_address;
+ Address m_pc;
+ AccessModeType m_access_mode;
+};
+
+// Output operator declaration
+ostream& operator<<(ostream& out, const Check& obj);
+
+// ******************* Definitions *******************
+
+// Output operator definition
+extern inline
+ostream& operator<<(ostream& out, const Check& obj)
+{
+ obj.print(out);
+ out << flush;
+ return out;
+}
+
+#endif //CHECK_H
diff --git a/src/mem/ruby/tester/CheckTable.cc b/src/mem/ruby/tester/CheckTable.cc
new file mode 100644
index 000000000..b8e57a646
--- /dev/null
+++ b/src/mem/ruby/tester/CheckTable.cc
@@ -0,0 +1,128 @@
+
+/*
+ * 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/CheckTable.hh"
+#include "mem/ruby/tester/Check.hh"
+#include "mem/gems_common/Map.hh"
+
+CheckTable::CheckTable()
+{
+ m_lookup_map_ptr = new Map<Address, Check*>;
+ 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; i<size1; i++) {
+ // Setup linear addresses
+ address.setAddress(physical);
+ addCheck(address);
+ physical += CHECK_SIZE;
+ }
+
+ // The next two sets are to get some limited false sharing and cache conflicts
+ physical = 1000;
+ for (int i=0; i<size2; i++) {
+ // Setup linear addresses
+ address.setAddress(physical);
+ addCheck(address);
+ physical += 256;
+ }
+
+ physical = 1000 + CHECK_SIZE;
+ for (int i=0; i<size2; i++) {
+ // Setup linear addresses
+ address.setAddress(physical);
+ addCheck(address);
+ physical += 256;
+ }
+}
+
+CheckTable::~CheckTable()
+{
+ int size = m_check_vector.size();
+ for (int i=0; i<size; i++) {
+ delete m_check_vector[i];
+ }
+ delete m_lookup_map_ptr;
+}
+
+void CheckTable::addCheck(const Address& address)
+{
+ if (log_int(CHECK_SIZE) != 0) {
+ if (address.bitSelect(0,CHECK_SIZE_BITS-1) != 0) {
+ ERROR_MSG("Check not aligned");
+ }
+ }
+
+ for (int i=0; i<CHECK_SIZE; i++) {
+ if (m_lookup_map_ptr->exist(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; i<CHECK_SIZE; i++) {
+ // Insert it once per byte
+ m_lookup_map_ptr->add(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..a7f486315
--- /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 "mem/ruby/common/Global.hh"
+#include "mem/gems_common/Vector.hh"
+
+class Address;
+class Check;
+template <class KEY_TYPE, class VALUE_TYPE> 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<Check*> m_check_vector;
+ Map<Address, Check*>* 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..e4d8addd2
--- /dev/null
+++ b/src/mem/ruby/tester/DetermGETXGenerator.cc
@@ -0,0 +1,160 @@
+
+/*
+ * 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 "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"
+
+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");
+
+ Addr data_addr = m_address.getAddress();
+ Request request(0, data_addr, 1, Flags<unsigned int>(), 3, 0, 0);
+ MemCmd::Command command;
+ command = MemCmd::WriteReq;
+
+ Packet pkt(&request, command, 0); // TODO -- make dest a real NodeID
+
+ sequencer()->makeRequest(&pkt);
+}
+
+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..1f5b67653
--- /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 "mem/ruby/common/Global.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 "mem/ruby/tester/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..bafaa18ae
--- /dev/null
+++ b/src/mem/ruby/tester/DetermInvGenerator.cc
@@ -0,0 +1,217 @@
+
+/*
+ * 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 "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"
+
+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);
+ 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");
+
+ Addr data_addr = m_address.getAddress();
+ Request request(0, data_addr, 1, Flags<unsigned int>(), 1, 0, 0);
+ MemCmd::Command command;
+ command = MemCmd::ReadReq;
+
+ Packet pkt(&request, command, 0); // TODO -- make dest a real NodeID
+
+ sequencer()->makeRequest(&pkt);
+
+}
+
+void DetermInvGenerator::initiateStore()
+{
+ DEBUG_MSG(TESTER_COMP, MedPrio, "initiating Store");
+
+ Addr data_addr = m_address.getAddress();
+ Request request(0, data_addr, 1, Flags<unsigned int>(), 3, 0, 0);
+ MemCmd::Command command;
+ command = MemCmd::WriteReq;
+
+ Packet pkt(&request, command, 0); // TODO -- make dest a real NodeID
+
+ sequencer()->makeRequest(&pkt);
+}
+
+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..4f0712fbe
--- /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 "mem/ruby/common/Global.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 "mem/ruby/tester/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..5adc7aa5c
--- /dev/null
+++ b/src/mem/ruby/tester/DetermSeriesGETSGenerator.cc
@@ -0,0 +1,158 @@
+
+/*
+ * 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/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)
+{
+ 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");
+
+ Addr data_addr = m_address.getAddress();
+ Request request(0, data_addr, 1, Flags<unsigned int>(), 3, 0, 0);
+ MemCmd::Command command;
+ command = MemCmd::ReadReq;
+ request.setFlags(Request::INST_FETCH);
+
+ Packet pkt(&request, command, 0); // TODO -- make dest a real NodeID
+
+ sequencer()->makeRequest(&pkt);
+}
+
+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..1e44dc3bc
--- /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 "mem/ruby/common/Global.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 "mem/ruby/tester/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..762672118
--- /dev/null
+++ b/src/mem/ruby/tester/DeterministicDriver.cc
@@ -0,0 +1,285 @@
+
+/*
+ * 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/system/System.hh"
+#include "mem/ruby/tester/DeterministicDriver.hh"
+#include "mem/ruby/eventqueue/RubyEventQueue.hh"
+#include "mem/ruby/tester/SpecifiedGenerator.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)
+{
+ 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; i<m_last_progress_vector.size(); i++) {
+ m_last_progress_vector[i] = 0;
+ }
+
+ m_load_vector.setSize(g_deterministic_addrs);
+ for (int i=0; i<m_load_vector.size(); i++) {
+ m_load_vector[i] = -1; // No processor last held it
+ }
+
+ m_store_vector.setSize(g_deterministic_addrs);
+ for (int i=0; i<m_store_vector.size(); i++) {
+ m_store_vector[i] = -1; // No processor last held it
+ }
+
+ m_generator_vector.setSize(RubyConfig::numberOfProcessors());
+
+ SpecifiedGeneratorType generator = string_to_SpecifiedGeneratorType(g_SpecifiedGenerator);
+
+ for (int i=0; i<m_generator_vector.size(); i++) {
+ switch (generator) {
+ case SpecifiedGeneratorType_DetermGETXGenerator:
+ m_generator_vector[i] = new DetermGETXGenerator(i, *this);
+ break;
+ case SpecifiedGeneratorType_DetermSeriesGETSGenerator:
+ m_generator_vector[i] = new DetermSeriesGETSGenerator(i, *this);
+ break;
+ case SpecifiedGeneratorType_DetermInvGenerator:
+ m_generator_vector[i] = new DetermInvGenerator(i, *this);
+ break;
+ default:
+ ERROR_MSG("Unexpected specified generator type");
+ }
+ }
+
+ // add the tester consumer to the global event queue
+ g_eventQueue_ptr->scheduleEvent(this, 1);
+}
+
+DeterministicDriver::~DeterministicDriver()
+{
+ for (int i=0; i<m_last_progress_vector.size(); i++) {
+ delete m_generator_vector[i];
+ }
+}
+
+void
+DeterministicDriver::hitCallback(Packet * pkt)
+{
+ 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<uint8>()+i));
+ }
+ }
+ m_generator_vector[proc]->performCallback(proc, data);
+ 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<NodeID> addr_vector)
+{
+ for (int i=0; i<addr_vector.size(); i++) {
+ if (((addr_vector[i]+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;
+ }
+ }
+ return false;
+}
+
+// test for a particular addr
+bool DeterministicDriver::isAddrReady(NodeID node, Vector<NodeID> 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<NodeID>& 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<NodeID> 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_number<addr_vector.size(); addr_number++) {
+ //for (int addr_number=addr_vector.size()-1; addr_number>0; 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<size; processor++) {
+ if ((current_time - m_last_progress_vector[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;
+ 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..710da7922
--- /dev/null
+++ b/src/mem/ruby/tester/DeterministicDriver.hh
@@ -0,0 +1,126 @@
+
+/*
+ * 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 "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 {
+public:
+ // Constructors
+ DeterministicDriver(RubySystem* 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(Packet* pkt);
+ 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<NodeID> addr_vector);
+ bool isAddrReady(NodeID node, Vector<NodeID> addr_vector);
+ bool isAddrReady(NodeID node, Vector<NodeID> addr_vector, Address addr);
+ void setNextAddr(NodeID node, Address addr, Vector<NodeID>& addr_vector);
+
+ // Private copy constructor and assignment operator
+ DeterministicDriver(const DeterministicDriver& obj);
+ DeterministicDriver& operator=(const DeterministicDriver& obj);
+
+ // Data Members (m_ prefix)
+ Vector<Time> m_last_progress_vector;
+ Vector<SpecifiedGenerator*> m_generator_vector;
+ Vector<NodeID> m_load_vector; // Processor last to load the addr
+ Vector<NodeID> m_store_vector; // Processor last to store the addr
+
+ int m_done_counter;
+ int m_loads_completed;
+ int m_stores_completed;
+ // enforces the previous node to have a certain # of completions
+ // before next node starts
+ int m_numCompletionsPerNode;
+
+ Histogram m_load_latency;
+ Histogram m_store_latency;
+ Time m_finish_time;
+ Time m_last_issue;
+};
+
+// Output operator declaration
+ostream& operator<<(ostream& out, const DeterministicDriver& obj);
+
+// ******************* Definitions *******************
+
+// Output operator definition
+extern inline
+ostream& operator<<(ostream& out, const DeterministicDriver& obj)
+{
+ obj.print(out);
+ out << flush;
+ return out;
+}
+
+#endif //DETERMINISTICDRIVER_H
diff --git a/src/mem/ruby/tester/Instruction.cc b/src/mem/ruby/tester/Instruction.cc
new file mode 100644
index 000000000..1f4d56fc2
--- /dev/null
+++ b/src/mem/ruby/tester/Instruction.cc
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 1999 by Mark Hill and David Wood for the Wisconsin
+ * Multifacet Project. ALL RIGHTS RESERVED.
+ *
+ * ##HEADER##
+ *
+ * This software is furnished under a license and may be used and
+ * copied only in accordance with the terms of such license and the
+ * inclusion of the above copyright notice. This software or any
+ * other copies thereof or any derivative works may not be provided or
+ * otherwise made available to any other persons. Title to and
+ * ownership of the software is retained by Mark Hill and David Wood.
+ * Any use of this software must include the above copyright notice.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS". THE LICENSOR MAKES NO
+ * WARRANTIES ABOUT ITS CORRECTNESS OR PERFORMANCE.
+ * */
+
+/*
+ * $Id: Instruction.C 1.2 05/08/26 00:54:48-05:00 xu@s0-32.cs.wisc.edu $
+ *
+ * Description:
+ *
+ */
+
+#include "mem/ruby/tester/Instruction.hh"
+
+Instruction::Instruction(){
+ m_opcode = Opcode_NUM_OPCODES;
+ m_address = Address(physical_address_t(0));
+}
+
+Instruction::Instruction(Opcode op, Address addr){
+ m_opcode = op;
+ m_address = addr;
+ assert(addr.getAddress() == 0);
+}
+
+void Instruction::init(Opcode op, Address addr){
+ m_opcode = op;
+ m_address = addr;
+ //cout << "Instruction(" << op << ", " << m_address << ")" << endl;
+}
+
+Opcode Instruction::getOpcode(){
+ return m_opcode;
+}
+
+Address Instruction::getAddress(){
+ return m_address;
+}
diff --git a/src/mem/ruby/tester/Instruction.hh b/src/mem/ruby/tester/Instruction.hh
new file mode 100644
index 000000000..fe5540b00
--- /dev/null
+++ b/src/mem/ruby/tester/Instruction.hh
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 1999 by Mark Hill and David Wood for the Wisconsin
+ * Multifacet Project. ALL RIGHTS RESERVED.
+ *
+ * ##HEADER##
+ *
+ * This software is furnished under a license and may be used and
+ * copied only in accordance with the terms of such license and the
+ * inclusion of the above copyright notice. This software or any
+ * other copies thereof or any derivative works may not be provided or
+ * otherwise made available to any other persons. Title to and
+ * ownership of the software is retained by Mark Hill and David Wood.
+ * Any use of this software must include the above copyright notice.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS". THE LICENSOR MAKES NO
+ * WARRANTIES ABOUT ITS CORRECTNESS OR PERFORMANCE.
+ * */
+
+/*
+ * $Id: Instruction.h 1.2 05/05/24 12:15:47-05:00 kmoore@balder.cs.wisc.edu $
+ *
+ * Description:
+ *
+ */
+
+#ifndef INSTRUCTION_H
+#define INSTRUCTION_H
+
+#include "mem/ruby/common/Address.hh"
+
+
+enum Opcode {
+ Opcode_BEGIN,
+ Opcode_LD,
+ Opcode_ST,
+ Opcode_INC,
+ Opcode_COMMIT,
+ Opcode_DONE,
+ Opcode_NUM_OPCODES
+};
+
+class Instruction {
+ public:
+ Instruction();
+ Instruction(Opcode op, Address addr);
+
+ void init(Opcode op, Address addr);
+ Opcode getOpcode();
+ Address getAddress();
+
+ private:
+ Opcode m_opcode;
+ Address m_address;
+
+};
+
+#endif
diff --git a/src/mem/ruby/tester/RaceyDriver.cc b/src/mem/ruby/tester/RaceyDriver.cc
new file mode 100644
index 000000000..c56557645
--- /dev/null
+++ b/src/mem/ruby/tester/RaceyDriver.cc
@@ -0,0 +1,135 @@
+
+/*
+ * 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/system/System.hh"
+#include "mem/ruby/tester/RaceyDriver.hh"
+#include "mem/ruby/eventqueue/RubyEventQueue.hh"
+#include "RaceyPseudoThread.hh"
+#include "mem/ruby/common/SubBlock.hh"
+
+RaceyDriver::RaceyDriver()
+{
+ // debug transition?
+ if(false) {
+ assert(g_debug_ptr);
+ g_debug_ptr->setDebugTime(1);
+ }
+
+ m_finish_time = 0;
+ m_done_counter = 0;
+ m_wakeup_thread0 = false;
+
+ // racey at least need two processors
+ assert(RubyConfig::numberOfProcessors() >= 2);
+
+ // init all racey pseudo threads
+ m_racey_pseudo_threads.setSize(RubyConfig::numberOfProcessors());
+ for (int i=0; i<m_racey_pseudo_threads.size(); i++) {
+ m_racey_pseudo_threads[i] = new RaceyPseudoThread(i, *this);
+ }
+
+ // add this driver to the global event queue, for deadlock detection
+ g_eventQueue_ptr->scheduleEvent(this, g_DEADLOCK_THRESHOLD);
+}
+
+RaceyDriver::~RaceyDriver()
+{
+ for (int i=0; i<m_racey_pseudo_threads.size(); i++) {
+ delete m_racey_pseudo_threads[i];
+ }
+}
+
+void RaceyDriver::hitCallback(NodeID proc, SubBlock& data, CacheRequestType type, int thread)
+{
+ DEBUG_EXPR(TESTER_COMP, MedPrio, data);
+ m_racey_pseudo_threads[proc]->performCallback(proc, data);
+}
+
+integer_t RaceyDriver::getInstructionCount(int procID) const
+{
+ return m_racey_pseudo_threads[procID]->getInstructionCounter();
+}
+
+int RaceyDriver::runningThreads()
+{
+ return RubyConfig::numberOfProcessors() - m_done_counter;
+}
+
+// used to wake up thread 0 whenever other thread finishes
+void RaceyDriver::registerThread0Wakeup()
+{
+ m_wakeup_thread0 = true;
+}
+
+void RaceyDriver::joinThread()
+{
+ m_done_counter++;
+ if (m_done_counter == RubyConfig::numberOfProcessors()) {
+ m_finish_time = g_eventQueue_ptr->getTime();
+ }
+
+ if(m_wakeup_thread0) {
+ g_eventQueue_ptr->scheduleEvent(m_racey_pseudo_threads[0], 1);
+ m_wakeup_thread0 = false;
+ }
+}
+
+void RaceyDriver::wakeup()
+{
+ // check for deadlock
+ for(int i = 0 ; i < m_racey_pseudo_threads.size(); i++) {
+ m_racey_pseudo_threads[i]->checkForDeadlock();
+ }
+
+ // schedule next wakeup
+ if (m_done_counter < RubyConfig::numberOfProcessors()) {
+ g_eventQueue_ptr->scheduleEvent(this, g_DEADLOCK_THRESHOLD);
+ }
+}
+
+void RaceyDriver::printStats(ostream& out) const
+{
+ assert(m_done_counter == RubyConfig::numberOfProcessors());
+ out << endl;
+ out << "RaceyDriver Stats" << endl;
+ out << "---------------------" << endl;
+
+ out << "execution signature: " << m_racey_pseudo_threads[0]->getSignature() << endl;
+ out << "finish_time: " << m_finish_time << endl;
+}
+
+void RaceyDriver::print(ostream& out) const
+{
+}
diff --git a/src/mem/ruby/tester/RaceyDriver.hh b/src/mem/ruby/tester/RaceyDriver.hh
new file mode 100644
index 000000000..a3e35b47c
--- /dev/null
+++ b/src/mem/ruby/tester/RaceyDriver.hh
@@ -0,0 +1,112 @@
+
+/*
+ * 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: The driver interface between racey pseudo threads and ruby
+ * memory timing simulator.
+ *
+ */
+
+#ifndef RACEYDRIVER_H
+#define RACEYDRIVER_H
+
+#include "mem/ruby/common/Global.hh"
+#include "mem/ruby/common/Driver.hh"
+
+class RaceyPseudoThread;
+
+class RaceyDriver : public Driver, public Consumer {
+public:
+ // Constructors
+ RaceyDriver();
+
+ // Destructor
+ ~RaceyDriver();
+
+ // Public Methods
+ int runningThreads();
+ void registerThread0Wakeup();
+ void joinThread();
+ bool Thread0Initialized() {
+ return m_racey_pseudo_threads[0]->getInitializedState();
+ };
+
+ void hitCallback(NodeID proc, SubBlock& data, CacheRequestType type, int thread);
+ void wakeup();
+ void printStats(ostream& out) const;
+ void clearStats() {}
+ void printConfig(ostream& out) const {}
+
+ integer_t getInstructionCount(int procID) const;
+
+ // save/load cpu states
+ void saveCPUStates(int cpu_id, string filename) {
+ m_racey_pseudo_threads[cpu_id]->saveCPUStates(filename);
+ };
+ void loadCPUStates(int cpu_id, string filename) {
+ m_racey_pseudo_threads[cpu_id]->loadCPUStates(filename);
+ };
+
+ // reset IC
+ void resetIC(int cpu_id) {
+ m_racey_pseudo_threads[cpu_id]->resetIC();
+ }
+
+ void print(ostream& out) const;
+private:
+
+ // Private copy constructor and assignment operator
+ RaceyDriver(const RaceyDriver& obj);
+ RaceyDriver& operator=(const RaceyDriver& obj);
+
+ // Data Members (m_ prefix)
+ Vector<RaceyPseudoThread*> m_racey_pseudo_threads;
+ int m_done_counter;
+ bool m_wakeup_thread0;
+
+ Time m_finish_time;
+};
+
+// Output operator declaration
+ostream& operator<<(ostream& out, const RaceyDriver& obj);
+
+// ******************* Definitions *******************
+
+// Output operator definition
+extern inline
+ostream& operator<<(ostream& out, const RaceyDriver& obj)
+{
+ obj.print(out);
+ out << flush;
+ return out;
+}
+
+#endif //RACEYDRIVER_H
diff --git a/src/mem/ruby/tester/RequestGenerator.cc b/src/mem/ruby/tester/RequestGenerator.cc
new file mode 100644
index 000000000..4ee24544f
--- /dev/null
+++ b/src/mem/ruby/tester/RequestGenerator.cc
@@ -0,0 +1,220 @@
+
+/*
+ * 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/RequestGenerator.hh"
+#include "mem/protocol/RequestGeneratorStatus.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/SyntheticDriver.hh"
+#include "mem/protocol/Chip.hh"
+
+RequestGenerator::RequestGenerator(NodeID node, SyntheticDriver& driver) :
+ m_driver(driver)
+{
+ m_status = RequestGeneratorStatus_Thinking;
+ m_last_transition = 0;
+ m_node = node;
+ pickAddress();
+ m_counter = 0;
+
+ //g_eventQueue_ptr->scheduleEvent(this, 1+(random() % 200));
+}
+
+RequestGenerator::~RequestGenerator()
+{
+}
+
+void RequestGenerator::wakeup()
+{
+ DEBUG_EXPR(TESTER_COMP, MedPrio, m_node);
+ DEBUG_EXPR(TESTER_COMP, MedPrio, m_status);
+
+ if (m_status == RequestGeneratorStatus_Thinking) {
+ m_status = RequestGeneratorStatus_Test_Pending;
+ m_last_transition = g_eventQueue_ptr->getTime();
+ initiateTest(); // Test
+ } else if (m_status == RequestGeneratorStatus_Holding) {
+ m_status = RequestGeneratorStatus_Release_Pending;
+ m_last_transition = g_eventQueue_ptr->getTime();
+ initiateRelease(); // Release
+ } else if (m_status == RequestGeneratorStatus_Before_Swap) {
+ m_status = RequestGeneratorStatus_Swap_Pending;
+ m_last_transition = g_eventQueue_ptr->getTime();
+ initiateSwap();
+ } else {
+ WARN_EXPR(m_status);
+ ERROR_MSG("Invalid status");
+ }
+}
+
+void RequestGenerator::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 == RequestGeneratorStatus_Test_Pending) {
+ // m_driver.recordTestLatency(g_eventQueue_ptr->getTime() - m_last_transition);
+ if (data.readByte() == LockStatus_Locked) {
+ // Locked - keep spinning
+ m_status = RequestGeneratorStatus_Thinking;
+ 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 = RequestGeneratorStatus_Before_Swap;
+ m_last_transition = g_eventQueue_ptr->getTime();
+ g_eventQueue_ptr->scheduleEvent(this, waitTime());
+ }
+ } else if (m_status == RequestGeneratorStatus_Swap_Pending) {
+ m_driver.recordSwapLatency(g_eventQueue_ptr->getTime() - m_last_transition);
+ if (data.readByte() == LockStatus_Locked) {
+ // We failed to aquire the lock
+ m_status = RequestGeneratorStatus_Thinking;
+ m_last_transition = g_eventQueue_ptr->getTime();
+ g_eventQueue_ptr->scheduleEvent(this, waitTime());
+ } else {
+ // We acquired the lock
+ data.writeByte(LockStatus_Locked);
+ m_status = RequestGeneratorStatus_Holding;
+ 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());
+ }
+ } else if (m_status == RequestGeneratorStatus_Release_Pending) {
+ m_driver.recordReleaseLatency(g_eventQueue_ptr->getTime() - m_last_transition);
+ // We're releasing the lock
+ data.writeByte(LockStatus_Unlocked);
+
+ m_counter++;
+ if (m_counter < g_tester_length) {
+ m_status = RequestGeneratorStatus_Thinking;
+ m_last_transition = g_eventQueue_ptr->getTime();
+ pickAddress();
+ g_eventQueue_ptr->scheduleEvent(this, thinkTime());
+ } else {
+ m_driver.reportDone();
+ m_status = RequestGeneratorStatus_Done;
+ m_last_transition = g_eventQueue_ptr->getTime();
+ }
+ } else {
+ WARN_EXPR(m_status);
+ ERROR_MSG("Invalid status");
+ }
+}
+
+int RequestGenerator::thinkTime() const
+{
+ return g_think_time;
+}
+
+int RequestGenerator::waitTime() const
+{
+ return g_wait_time;
+}
+
+int RequestGenerator::holdTime() const
+{
+ return g_hold_time;
+}
+
+void RequestGenerator::pickAddress()
+{
+ assert(m_status == RequestGeneratorStatus_Thinking);
+ m_address = m_driver.pickAddress(m_node);
+}
+
+void RequestGenerator::initiateTest()
+{
+ DEBUG_MSG(TESTER_COMP, MedPrio, "initiating Test");
+
+ Addr data_addr = m_address.getAddress();
+ Request request(0, data_addr, 1, Flags<unsigned int>(), 1, 0, 0);
+ MemCmd::Command command;
+ command = MemCmd::ReadReq;
+
+ Packet pkt(&request, command, 0); // TODO -- make dest a real NodeID
+
+ sequencer()->makeRequest(&pkt);
+}
+
+void RequestGenerator::initiateSwap()
+{
+ DEBUG_MSG(TESTER_COMP, MedPrio, "initiating Swap");
+
+ Addr data_addr = m_address.getAddress();
+ Request request(0, data_addr, 1, Flags<unsigned int>(), 2, 0, 0);
+ MemCmd::Command command;
+ command = MemCmd::SwapReq;
+
+ Packet pkt(&request, command, 0); // TODO -- make dest a real NodeID
+
+ sequencer()->makeRequest(&pkt);
+}
+
+void RequestGenerator::initiateRelease()
+{
+ DEBUG_MSG(TESTER_COMP, MedPrio, "initiating Release");
+
+ Addr data_addr = m_address.getAddress();
+ Request request(0, data_addr, 1, Flags<unsigned int>(), 3, 0, 0);
+ MemCmd::Command command;
+ command = MemCmd::WriteReq;
+
+ Packet pkt(&request, command, 0); // TODO -- make dest a real NodeID
+
+ sequencer()->makeRequest(&pkt);
+}
+
+Sequencer* RequestGenerator::sequencer() const
+{
+ return g_system_ptr->getChip(m_node/RubyConfig::numberOfProcsPerChip())->getSequencer(m_node%RubyConfig::numberOfProcsPerChip());
+}
+
+void RequestGenerator::print(ostream& out) const
+{
+ out << "[RequestGenerator]" << endl;
+}
+
diff --git a/src/mem/ruby/tester/RequestGenerator.hh b/src/mem/ruby/tester/RequestGenerator.hh
new file mode 100644
index 000000000..2859eb436
--- /dev/null
+++ b/src/mem/ruby/tester/RequestGenerator.hh
@@ -0,0 +1,102 @@
+
+/*
+ * 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 REQUESTGENERATOR_H
+#define REQUESTGENERATOR_H
+
+#include "mem/ruby/common/Global.hh"
+#include "mem/ruby/common/Consumer.hh"
+#include "mem/protocol/RequestGeneratorStatus.hh"
+#include "mem/ruby/system/NodeID.hh"
+#include "mem/ruby/common/Address.hh"
+
+class Sequencer;
+class SubBlock;
+class SyntheticDriver;
+
+class RequestGenerator : public Consumer {
+public:
+ // Constructors
+ RequestGenerator(NodeID node, SyntheticDriver& driver);
+
+ // Destructor
+ ~RequestGenerator();
+
+ // 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 initiateTest();
+ void initiateSwap();
+ void initiateRelease();
+ void pickAddress();
+ Sequencer* sequencer() const;
+
+ // Private copy constructor and assignment operator
+ RequestGenerator(const RequestGenerator& obj);
+ RequestGenerator& operator=(const RequestGenerator& obj);
+
+ // Data Members (m_ prefix)
+ SyntheticDriver& m_driver;
+ NodeID m_node;
+ RequestGeneratorStatus m_status;
+ int m_counter;
+ Time m_last_transition;
+ Address m_address;
+};
+
+// Output operator declaration
+ostream& operator<<(ostream& out, const RequestGenerator& obj);
+
+// ******************* Definitions *******************
+
+// Output operator definition
+extern inline
+ostream& operator<<(ostream& out, const RequestGenerator& obj)
+{
+ obj.print(out);
+ out << flush;
+ return out;
+}
+
+#endif //REQUESTGENERATOR_H
+
diff --git a/src/mem/ruby/tester/SConscript b/src/mem/ruby/tester/SConscript
new file mode 100644
index 000000000..6409b4f50
--- /dev/null
+++ b/src/mem/ruby/tester/SConscript
@@ -0,0 +1,46 @@
+# -*- mode:python -*-
+
+# Copyright (c) 2009 The Hewlett-Packard Development Company
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met: redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer;
+# redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution;
+# neither the name of the copyright holders nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+# Authors: Nathan Binkert
+
+Import('*')
+
+if not env['RUBY']:
+ Return()
+
+Source('Check.cc')
+Source('CheckTable.cc')
+Source('DetermGETXGenerator.cc')
+Source('DetermInvGenerator.cc')
+Source('DetermSeriesGETSGenerator.cc')
+Source('DeterministicDriver.cc')
+Source('Instruction.cc')
+Source('RequestGenerator.cc')
+Source('SpecifiedGenerator.cc')
+Source('SyntheticDriver.cc')
+Source('Tester.cc')
diff --git a/src/mem/ruby/tester/SpecifiedGenerator.cc b/src/mem/ruby/tester/SpecifiedGenerator.cc
new file mode 100644
index 000000000..17f827ee8
--- /dev/null
+++ b/src/mem/ruby/tester/SpecifiedGenerator.cc
@@ -0,0 +1,48 @@
+
+/*
+ * 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/SpecifiedGenerator.hh"
+#include "mem/ruby/system/Sequencer.hh"
+#include "mem/ruby/system/System.hh"
+#include "mem/ruby/common/SubBlock.hh"
+#include "mem/ruby/tester/SyntheticDriver.hh"
+
+SpecifiedGenerator::SpecifiedGenerator()
+{
+}
+
+SpecifiedGenerator::~SpecifiedGenerator()
+{
+}
+
diff --git a/src/mem/ruby/tester/SpecifiedGenerator.hh b/src/mem/ruby/tester/SpecifiedGenerator.hh
new file mode 100644
index 000000000..9b4c71623
--- /dev/null
+++ b/src/mem/ruby/tester/SpecifiedGenerator.hh
@@ -0,0 +1,69 @@
+
+/*
+ * 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 SPECIFIEDGENERATOR_H
+#define SPECIFIEDGENERATOR_H
+
+#include "mem/ruby/common/Global.hh"
+#include "mem/ruby/common/Consumer.hh"
+#include "mem/ruby/system/NodeID.hh"
+
+class Sequencer;
+class SubBlock;
+
+class SpecifiedGenerator : public Consumer {
+public:
+ // Constructors
+ SpecifiedGenerator();
+
+ // Destructor
+ virtual ~SpecifiedGenerator() = 0;
+
+ // Public Methods
+ virtual void wakeup() = 0;
+ virtual void performCallback(NodeID proc, SubBlock& data) = 0;
+
+ virtual void print(ostream& out) const = 0;
+protected:
+ // accessible by subclasses
+
+private:
+ // inaccessible by subclasses
+
+};
+
+#endif //SPECIFIEDGENERATOR_H
+
diff --git a/src/mem/ruby/tester/SyntheticDriver.cc b/src/mem/ruby/tester/SyntheticDriver.cc
new file mode 100644
index 000000000..f19baa202
--- /dev/null
+++ b/src/mem/ruby/tester/SyntheticDriver.cc
@@ -0,0 +1,286 @@
+
+/*
+ * 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/system/System.hh"
+#include "mem/ruby/tester/SyntheticDriver.hh"
+#include "mem/ruby/eventqueue/RubyEventQueue.hh"
+#include "mem/ruby/tester/RequestGenerator.hh"
+#include "mem/ruby/common/SubBlock.hh"
+#include "mem/protocol/Chip.hh"
+
+SyntheticDriver::SyntheticDriver(RubySystem* sys_ptr)
+{
+ m_finish_time = 0;
+ m_done_counter = 0;
+
+ m_last_progress_vector.setSize(RubyConfig::numberOfProcessors());
+ for (int i=0; i<m_last_progress_vector.size(); i++) {
+ m_last_progress_vector[i] = 0;
+ }
+
+ m_lock_vector.setSize(g_synthetic_locks);
+ for (int i=0; i<m_lock_vector.size(); i++) {
+ m_lock_vector[i] = -1; // No processor last held it
+ }
+
+ m_request_generator_vector.setSize(RubyConfig::numberOfProcessors());
+ for (int i=0; i<m_request_generator_vector.size(); i++) {
+ if(XACT_MEMORY){
+ //m_request_generator_vector[i] = new XactRequestGenerator(i, *this);
+ } else {
+ m_request_generator_vector[i] = new RequestGenerator(i, *this);
+ }
+ }
+
+ // add the tester consumer to the global event queue
+ g_eventQueue_ptr->scheduleEvent(this, 1);
+}
+
+SyntheticDriver::~SyntheticDriver()
+{
+ for (int i=0; i<m_last_progress_vector.size(); i++) {
+ delete m_request_generator_vector[i];
+ }
+}
+
+void
+SyntheticDriver::hitCallback(Packet * pkt)
+{
+ 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<uint8>()+i));
+ }
+ }
+ m_request_generator_vector[proc]->performCallback(proc, data);
+ m_last_progress_vector[proc] = g_eventQueue_ptr->getTime();
+}
+
+void SyntheticDriver::abortCallback(NodeID proc, SubBlock& data, CacheRequestType type, int thread)
+{
+ //cout << "SyntheticDriver::abortCallback" << endl;
+ DEBUG_EXPR(TESTER_COMP, MedPrio, data);
+
+ if(XACT_MEMORY){
+ //XactRequestGenerator* reqGen = static_cast<XactRequestGenerator*>(m_request_generator_vector[proc]);
+ //reqGen->abortTransaction();
+ //reqGen->performCallback(proc, data);
+ } else {
+ m_request_generator_vector[proc]->performCallback(proc, data);
+ }
+
+ // Mark that we made progress
+ m_last_progress_vector[proc] = g_eventQueue_ptr->getTime();
+}
+
+// For Transactional Memory
+/*
+// called whenever we send a nack
+void SyntheticDriver::notifySendNack( int proc, const Address & addr, uint64 remote_timestamp, const MachineID & remote_id ){
+ if(XACT_MEMORY){
+ //XactRequestGenerator* reqGen = static_cast<XactRequestGenerator*>(m_request_generator_vector[proc]);
+ //reqGen->notifySendNack(addr, remote_timestamp, remote_id);
+ }
+ else{
+ cout << "notifySendNack NOT USING TM" << endl;
+ ASSERT(0);
+ }
+}
+
+// called whenever we receive a NACK
+// Either for a demand request or log store
+void SyntheticDriver::notifyReceiveNack( int proc, const Address & addr, uint64 remote_timestamp, const MachineID & remote_id ){
+ if(XACT_MEMORY){
+ //XactRequestGenerator* reqGen = static_cast<XactRequestGenerator*>(m_request_generator_vector[proc]);
+ //reqGen->notifyReceiveNack(addr, remote_timestamp, remote_id);
+ }
+ else{
+ cout << "notifyReceiveNack NOT USING TM" << endl;
+ ASSERT(0);
+ }
+}
+
+// called whenever we received ALL the NACKs. Take abort or retry action here
+void SyntheticDriver::notifyReceiveNackFinal(int proc, const Address & addr){
+ if(XACT_MEMORY){
+ //XactRequestGenerator* reqGen = static_cast<XactRequestGenerator*>(m_request_generator_vector[proc]);
+ //reqGen->notifyReceiveNackFinal(addr);
+ }
+ else{
+ ASSERT(0);
+ }
+}
+
+// called during abort handling
+// void SyntheticDriver::notifyAbortStart( const Address & handlerPC ){
+
+// }
+
+// void SyntheticDriver::notifyAbortComplete( const Address & newPC ){
+
+// }
+*/
+
+Address SyntheticDriver::pickAddress(NodeID node)
+{
+ // This methods picks a random lock that we were NOT that last
+ // processor to acquire. Why? Without this change 2 and 4
+ // processor runs, the odds of having the lock in your cache in
+ // read/write state is 50% or 25%, respectively. This effect can
+ // make our 'throughput per processor' results look too strange.
+
+ Address addr;
+ // FIXME - make this a parameter of the workload
+ int lock_number = 0;
+ int counter = 0;
+ while (1) {
+ // Pick a random lock
+ lock_number = random() % m_lock_vector.size();
+
+ // Were we the last to acquire the lock?
+ if (m_lock_vector[lock_number] != node) {
+ break;
+ }
+
+ // Don't keep trying forever, since if there is only one lock, we're always the last to try to obtain the lock
+ counter++;
+ if (counter > 10) {
+ break;
+ }
+ }
+
+ // We're going to acquire it soon, so we can update the last
+ // processor to hold the lock at this time
+ m_lock_vector[lock_number] = node;
+
+ // One lock per cache line
+ addr.setAddress(lock_number * RubyConfig::dataBlockBytes());
+ return addr;
+}
+
+void SyntheticDriver::reportDone()
+{
+ m_done_counter++;
+ if (m_done_counter == RubyConfig::numberOfProcessors()) {
+ m_finish_time = g_eventQueue_ptr->getTime();
+ }
+}
+
+void SyntheticDriver::recordTestLatency(Time time)
+{
+ m_test_latency.add(time);
+}
+
+void SyntheticDriver::recordSwapLatency(Time time)
+{
+ m_swap_latency.add(time);
+}
+
+void SyntheticDriver::recordReleaseLatency(Time time)
+{
+ m_release_latency.add(time);
+}
+
+void SyntheticDriver::wakeup()
+{
+ // checkForDeadlock();
+ if (m_done_counter < RubyConfig::numberOfProcessors()) {
+ g_eventQueue_ptr->scheduleEvent(this, g_DEADLOCK_THRESHOLD);
+ }
+}
+
+void SyntheticDriver::checkForDeadlock()
+{
+ int size = m_last_progress_vector.size();
+ Time current_time = g_eventQueue_ptr->getTime();
+ for (int processor=0; processor<size; processor++) {
+ if ((current_time - m_last_progress_vector[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.");
+ }
+ }
+}
+
+integer_t SyntheticDriver::readPhysicalMemory(int procID, physical_address_t address,
+ int len ){
+ char buffer[8];
+ ASSERT(len <= 8);
+ Sequencer* seq = g_system_ptr->getChip(procID/RubyConfig::numberOfProcsPerChip())->getSequencer(procID%RubyConfig::numberOfProcsPerChip());
+ assert(seq != NULL);
+ bool found = seq->getRubyMemoryValue(Address(address), buffer, len );
+ ASSERT(found);
+ return *((integer_t *) buffer);
+}
+
+void SyntheticDriver::writePhysicalMemory( int procID, physical_address_t address,
+ integer_t value, int len ){
+ char buffer[8];
+ ASSERT(len <= 8);
+
+ memcpy(buffer, (const void*) &value, len);
+ DEBUG_EXPR(TESTER_COMP, MedPrio, "");
+ Sequencer* seq = g_system_ptr->getChip(procID/RubyConfig::numberOfProcsPerChip())->getSequencer(procID%RubyConfig::numberOfProcsPerChip());
+ assert(seq != NULL);
+ bool found = seq->setRubyMemoryValue(Address(address), buffer, len );
+ ASSERT(found);
+ //return found;
+}
+
+void SyntheticDriver::printStats(ostream& out) const
+{
+ out << endl;
+ out << "SyntheticDriver Stats" << endl;
+ out << "---------------------" << endl;
+
+ out << "synthetic_finish_time: " << m_finish_time << endl;
+ out << "test_latency: " << m_test_latency << endl;
+ out << "swap_latency: " << m_swap_latency << endl;
+ out << "release_latency: " << m_release_latency << endl;
+}
+
+void SyntheticDriver::print(ostream& out) const
+{
+}
diff --git a/src/mem/ruby/tester/SyntheticDriver.hh b/src/mem/ruby/tester/SyntheticDriver.hh
new file mode 100644
index 000000000..18c463e88
--- /dev/null
+++ b/src/mem/ruby/tester/SyntheticDriver.hh
@@ -0,0 +1,118 @@
+
+/*
+ * 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 SYNTHETICDRIVER_H
+#define SYNTHETICDRIVER_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 RequestGenerator;
+
+class SyntheticDriver : public Driver, public Consumer {
+public:
+ // Constructors
+ SyntheticDriver(RubySystem* sys_ptr);
+
+ // Destructor
+ ~SyntheticDriver();
+
+ // Public Methods
+ Address pickAddress(NodeID node);
+ void reportDone();
+ void recordTestLatency(Time time);
+ void recordSwapLatency(Time time);
+ void recordReleaseLatency(Time time);
+
+ void hitCallback(Packet* pkt);
+ void conflictCallback(NodeID proc, SubBlock& data, CacheRequestType type, int thread) {assert(0);}
+ void abortCallback(NodeID proc, SubBlock& data, CacheRequestType type, int thread);
+ void wakeup();
+ void printStats(ostream& out) const;
+ void clearStats() {}
+ void printConfig(ostream& out) const {}
+
+ integer_t readPhysicalMemory(int procID, physical_address_t address,
+ int len );
+
+ void writePhysicalMemory( int procID, physical_address_t address,
+ integer_t value, int len );
+
+ void print(ostream& out) const;
+
+ // For handling NACKs/retries
+ //void notifySendNack( int procID, const Address & addr, uint64 remote_timestamp, const MachineID & remote_id);
+ //void notifyReceiveNack( int procID, const Address & addr, uint64 remote_timestamp, const MachineID & remote_id);
+ //void notifyReceiveNackFinal( int procID, const Address & addr);
+
+private:
+ // Private Methods
+ void checkForDeadlock();
+
+ // Private copy constructor and assignment operator
+ SyntheticDriver(const SyntheticDriver& obj);
+ SyntheticDriver& operator=(const SyntheticDriver& obj);
+
+ // Data Members (m_ prefix)
+ Vector<Time> m_last_progress_vector;
+ Vector<RequestGenerator*> m_request_generator_vector;
+ Vector<NodeID> m_lock_vector; // Processor last to hold the lock
+ int m_done_counter;
+
+ Histogram m_test_latency;
+ Histogram m_swap_latency;
+ Histogram m_release_latency;
+ Time m_finish_time;
+};
+
+// Output operator declaration
+ostream& operator<<(ostream& out, const SyntheticDriver& obj);
+
+// ******************* Definitions *******************
+
+// Output operator definition
+extern inline
+ostream& operator<<(ostream& out, const SyntheticDriver& obj)
+{
+ obj.print(out);
+ out << flush;
+ return out;
+}
+
+#endif //SYNTHETICDRIVER_H
diff --git a/src/mem/ruby/tester/Tester.cc b/src/mem/ruby/tester/Tester.cc
new file mode 100644
index 000000000..eafc04a92
--- /dev/null
+++ b/src/mem/ruby/tester/Tester.cc
@@ -0,0 +1,112 @@
+
+/*
+ * 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/system/System.hh"
+#include "mem/ruby/tester/Tester.hh"
+#include "mem/ruby/eventqueue/RubyEventQueue.hh"
+#include "mem/ruby/common/SubBlock.hh"
+#include "mem/ruby/tester/Check.hh"
+#include "mem/protocol/Chip.hh"
+
+Tester::Tester(RubySystem* sys_ptr)
+{
+ g_callback_counter = 0;
+
+ // add the tester consumer to the global event queue
+ g_eventQueue_ptr->scheduleEvent(this, 1);
+
+ m_last_progress_vector.setSize(RubyConfig::numberOfProcessors());
+ for (int i=0; i<m_last_progress_vector.size(); i++) {
+ m_last_progress_vector[i] = 0;
+ }
+}
+
+Tester::~Tester()
+{
+}
+
+void Tester::hitCallback(NodeID proc, SubBlock& data, CacheRequestType type, int thread)
+{
+ // Mark that we made progress
+ m_last_progress_vector[proc] = g_eventQueue_ptr->getTime();
+ g_callback_counter++;
+
+ // This tells us our store has 'completed' or for a load gives us
+ // back the data to make the check
+ DEBUG_EXPR(TESTER_COMP, MedPrio, proc);
+ DEBUG_EXPR(TESTER_COMP, MedPrio, data);
+ Check* check_ptr = m_checkTable.getCheck(data.getAddress());
+ assert(check_ptr != NULL);
+ check_ptr->performCallback(proc, data);
+
+}
+
+void Tester::wakeup()
+{
+ if (g_callback_counter < g_tester_length) {
+ // Try to perform an action or check
+ Check* check_ptr = m_checkTable.getRandomCheck();
+ assert(check_ptr != NULL);
+ check_ptr->initiate();
+
+ checkForDeadlock();
+
+ g_eventQueue_ptr->scheduleEvent(this, 2);
+ }
+}
+
+void Tester::checkForDeadlock()
+{
+ int size = m_last_progress_vector.size();
+ Time current_time = g_eventQueue_ptr->getTime();
+ for (int processor=0; processor<size; processor++) {
+ if ((current_time - m_last_progress_vector[processor]) > g_DEADLOCK_THRESHOLD) {
+ WARN_EXPR(current_time);
+ WARN_EXPR(m_last_progress_vector[processor]);
+ WARN_EXPR(current_time - m_last_progress_vector[processor]);
+ WARN_EXPR(processor);
+ Sequencer* seq_ptr = g_system_ptr->getChip(processor/RubyConfig::numberOfProcsPerChip())->getSequencer(processor%RubyConfig::numberOfProcsPerChip());
+ assert(seq_ptr != NULL);
+ WARN_EXPR(*seq_ptr);
+ ERROR_MSG("Deadlock detected.");
+ }
+ }
+}
+
+void Tester::print(ostream& out) const
+{
+ out << "[Tester]" << endl;
+}
+
diff --git a/src/mem/ruby/tester/Tester.hh b/src/mem/ruby/tester/Tester.hh
new file mode 100644
index 000000000..7b721e038
--- /dev/null
+++ b/src/mem/ruby/tester/Tester.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 TESTER_H
+#define TESTER_H
+
+#include "mem/ruby/common/Global.hh"
+#include "mem/ruby/common/Driver.hh"
+#include "mem/ruby/tester/CheckTable.hh"
+#include "mem/protocol/CacheRequestType.hh"
+
+class RubySystem;
+
+class Tester : public Driver, public Consumer {
+public:
+ // Constructors
+ Tester(RubySystem* sys_ptr);
+
+ // Destructor
+ ~Tester();
+
+ // Public Methods
+
+ 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();
+
+ // Private copy constructor and assignment operator
+ Tester(const Tester& obj);
+ Tester& operator=(const Tester& obj);
+
+ // Data Members (m_ prefix)
+
+ CheckTable m_checkTable;
+ Vector<Time> m_last_progress_vector;
+};
+
+// Output operator declaration
+ostream& operator<<(ostream& out, const Tester& obj);
+
+// ******************* Definitions *******************
+
+// Output operator definition
+extern inline
+ostream& operator<<(ostream& out, const Tester& obj)
+{
+ obj.print(out);
+ out << flush;
+ return out;
+}
+
+#endif //TESTER_H
diff --git a/src/mem/ruby/tester/main.cc b/src/mem/ruby/tester/main.cc
new file mode 100644
index 000000000..ba835b488
--- /dev/null
+++ b/src/mem/ruby/tester/main.cc
@@ -0,0 +1,48 @@
+
+/*
+ * 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/main.hh"
+#include "mem/ruby/eventqueue/RubyEventQueue.hh"
+#include "mem/ruby/config/RubyConfig.hh"
+//#include "mem/ruby/tester/test_framework.hh"
+
+// *******************
+// *** tester main ***
+// *******************
+
+int main(int argc, char *argv[])
+{
+ //dsm: PRUNED
+ //tester_main(argc, argv);
+}
diff --git a/src/mem/ruby/tester/main.hh b/src/mem/ruby/tester/main.hh
new file mode 100644
index 000000000..3708d770d
--- /dev/null
+++ b/src/mem/ruby/tester/main.hh
@@ -0,0 +1,35 @@
+
+/*
+ * 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 MAIN_H
+#define MAIN_H
+
+#include "mem/ruby/common/Global.hh"
+
+#endif //MAIN_H
diff --git a/src/mem/ruby/tester/test_framework.cc b/src/mem/ruby/tester/test_framework.cc
new file mode 100644
index 000000000..9886adc8d
--- /dev/null
+++ b/src/mem/ruby/tester/test_framework.cc
@@ -0,0 +1,426 @@
+
+/*
+ * 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/protocol/protocol_name.hh"
+#include "mem/ruby/tester/test_framework.hh"
+#include "mem/ruby/system/System.hh"
+#include "mem/ruby/init.hh"
+#include "mem/ruby/tester/Tester.hh"
+#include "mem/ruby/eventqueue/RubyEventQueue.hh"
+#include "getopt.hh"
+#include "mem/ruby/network/Network.hh"
+#include "mem/ruby/recorder/CacheRecorder.hh"
+#include "mem/ruby/recorder/Tracer.hh"
+
+using namespace std;
+#include <string>
+#include <map>
+
+// Maurice
+// extern "C" {
+// #include "simics/api.hh"
+// };
+
+#include "mem/gems_common/ioutil/confio.hh"
+#include "mem/gems_common/ioutil/initvar.hh"
+
+// A generated file containing the default tester parameters in string form
+// The defaults are stored in the variables
+// global_default_param and global_default_tester_param
+#include "mem/ruby/default_param.hh"
+#include "mem/ruby/tester_param.hh"
+
+static void parseOptions(int argc, char **argv);
+static void usageInstructions();
+static void checkArg(char ch);
+static void tester_record_cache();
+static void tester_playback_trace();
+static void tester_initialize(int argc, char **argv);
+static void tester_destroy();
+
+static string trace_filename;
+char * my_default_param;
+initvar_t * my_initvar;
+
+void tester_main(int argc, char **argv)
+{
+ tester_initialize(argc, argv);
+
+ if (trace_filename != "") {
+ // playback a trace (for multicast-mask prediction)
+ tester_playback_trace();
+ } else {
+ // test code to create a trace
+ if (!(g_SYNTHETIC_DRIVER || g_DETERMINISTIC_DRIVER) && trace_filename == "") {
+ g_system_ptr->getTracer()->startTrace("ruby.trace.gz");
+ g_eventQueue_ptr->triggerEvents(g_eventQueue_ptr->getTime() + 10000);
+ g_system_ptr->getTracer()->stopTrace();
+ }
+
+ g_eventQueue_ptr->triggerAllEvents();
+
+ // This call is placed here to make sure the cache dump code doesn't fall victim to code rot
+ if (!(g_SYNTHETIC_DRIVER || g_DETERMINISTIC_DRIVER)) {
+ tester_record_cache();
+ }
+ }
+ tester_destroy();
+}
+
+static void tester_allocate( void )
+{
+ init_simulator();
+}
+
+static void tester_generate_values( void )
+{
+}
+
+void tester_initialize(int argc, char **argv)
+{
+ int param_len = strlen( global_default_param ) + strlen( global_default_tester_param ) + 1;
+ char *default_param = (char *) malloc( sizeof(char) * param_len );
+ my_default_param = default_param;
+ strcpy( default_param, global_default_param );
+ strcat( default_param, global_default_tester_param );
+
+ // when the initvar object is created, it reads the configuration default
+ // -for the tester, the configuration defaults in config/tester.defaults
+
+ /** note: default_param is included twice in the tester:
+ * -once in init.C
+ * -again in this file
+ */
+ initvar_t *ruby_initvar = new initvar_t( "ruby", "../../../ruby/",
+ default_param,
+ &tester_allocate,
+ &tester_generate_values,
+ NULL,
+ NULL );
+ my_initvar = ruby_initvar;
+ ruby_initvar->checkInitialization();
+ parseOptions(argc, argv);
+
+ ruby_initvar->allocate();
+
+ g_system_ptr->printConfig(cout);
+ cout << "Testing clear stats...";
+ g_system_ptr->clearStats();
+ cout << "Done." << endl;
+ //free( default_param );
+ //delete ruby_initvar;
+}
+
+void tester_destroy()
+{
+ g_system_ptr->printStats(cout);
+ g_debug_ptr->closeDebugOutputFile();
+
+ free(my_default_param);
+ delete my_initvar;
+ // Clean up
+ destroy_simulator();
+ cerr << "Success: " << CURRENT_PROTOCOL << endl;
+}
+
+void tester_install_opal(mf_opal_api_t* opal_api, mf_ruby_api_t* ruby_api)
+{
+ std::cout << __FILE__ << "(" << __LINE__ << "): Not implemented" << std::endl;
+}
+
+void tester_record_cache()
+{
+ cout << "Testing recording of cache contents" << endl;
+ CacheRecorder recorder;
+ g_system_ptr->recordCacheContents(recorder);
+ int written = recorder.dumpRecords("ruby.caches.gz");
+ int read = Tracer::playbackTrace("ruby.caches.gz");
+ assert(read == written);
+ cout << "Testing recording of cache contents completed" << endl;
+}
+
+void tester_playback_trace()
+{
+ assert(trace_filename != "");
+ cout << "Reading trace from file '" << trace_filename << "'..." << endl;
+ int read = Tracer::playbackTrace(trace_filename);
+ cout << "(" << read << " requests read)" << endl;
+ if (read == 0) {
+ ERROR_MSG("Zero items read from tracefile.");
+ }
+}
+
+// ************************************************************************
+// *** Functions for parsing the command line parameters for the tester ***
+// ************************************************************************
+
+static struct option const long_options[] =
+{
+ {"help", no_argument, NULL, 'h'},
+ {"processors", required_argument, NULL, 'p'},
+ {"length", required_argument, NULL, 'l'},
+ {"random", required_argument, NULL, 'r'},
+ {"trace_input", required_argument, NULL, 'z'},
+ {"component", required_argument, NULL, 'c'},
+ {"verbosity", required_argument, NULL, 'v'},
+ {"debug_output_file", required_argument, NULL, 'o'},
+ {"start", required_argument, NULL, 's'},
+ {"bandwidth", required_argument, NULL, 'b'},
+ {"threshold", required_argument, NULL, 't'},
+ {"think_time", required_argument, NULL, 'k'},
+ {"locks", required_argument, NULL, 'q'},
+ {"network", required_argument, NULL, 'n'},
+ {"procs_per_chip", required_argument, NULL, 'a'},
+ {"l2_caches", required_argument, NULL, 'e'},
+ {"memories", required_argument, NULL, 'm'},
+ {NULL, 0, NULL, 0}
+};
+
+static void parseOptions(int argc, char **argv)
+{
+ cout << "Parsing command line arguments:" << endl;
+
+ // construct the short arguments string
+ int counter = 0;
+ string short_options;
+ while (long_options[counter].name != NULL) {
+ short_options += char(long_options[counter].val);
+ if (long_options[counter].has_arg == required_argument) {
+ short_options += char(':');
+ }
+ counter++;
+ }
+
+ char c;
+ /* Parse command line options. */
+ bool error;
+ while ((c = getopt_long (argc, argv, short_options.c_str(), long_options, (int *) 0)) != EOF) {
+ switch (c) {
+ case 0:
+ break;
+
+ case 'c':
+ checkArg(c);
+ cout << " component filter string = " << optarg << endl;
+ error = Debug::checkFilterString( optarg );
+ if (error) {
+ usageInstructions();
+ }
+ DEBUG_FILTER_STRING = strdup( optarg );
+ break;
+
+ case 'h':
+ usageInstructions();
+ break;
+
+ case 'v':
+ checkArg(c);
+ cout << " verbosity string = " << optarg << endl;
+ error = Debug::checkVerbosityString(optarg);
+ if (error) {
+ usageInstructions();
+ }
+ DEBUG_VERBOSITY_STRING = strdup( optarg );
+ break;
+
+ case 'r': {
+ checkArg(c);
+ if (string(optarg) == "random") {
+ g_RANDOM_SEED = time(NULL);
+ } else {
+ g_RANDOM_SEED = atoi(optarg);
+ if (g_RANDOM_SEED == 0) {
+ usageInstructions();
+ }
+ }
+ break;
+ }
+
+ case 'l': {
+ checkArg(c);
+ g_tester_length = atoi(optarg);
+ cout << " length of run = " << g_tester_length << endl;
+ if (g_tester_length == 0) {
+ usageInstructions();
+ }
+ break;
+ }
+
+ case 'q': {
+ checkArg(c);
+ g_synthetic_locks = atoi(optarg);
+ cout << " locks in synthetic workload = " << g_synthetic_locks << endl;
+ if (g_synthetic_locks == 0) {
+ usageInstructions();
+ }
+ break;
+ }
+
+ case 'p': {
+ checkArg(c);
+ g_NUM_PROCESSORS = atoi(optarg);
+ break;
+ }
+
+ case 'a': {
+ checkArg(c);
+ g_PROCS_PER_CHIP = atoi(optarg);
+ cout << " g_PROCS_PER_CHIP: " << g_PROCS_PER_CHIP << endl;
+ break;
+ }
+
+ case 'e': {
+ checkArg(c);
+ g_NUM_L2_BANKS = atoi(optarg);
+ cout << " g_NUM_L2_BANKS: " << g_NUM_L2_BANKS << endl;
+ break;
+ }
+
+ case 'm': {
+ checkArg(c);
+ g_NUM_MEMORIES = atoi(optarg);
+ cout << " g_NUM_MEMORIES: " << g_NUM_MEMORIES << endl;
+ break;
+ }
+
+ case 's': {
+ checkArg(c);
+ long long start_time = atoll(optarg);
+ cout << " debug start cycle = " << start_time << endl;
+ if (start_time == 0) {
+ usageInstructions();
+ }
+ DEBUG_START_TIME = start_time;
+ break;
+ }
+
+ case 'b': {
+ checkArg(c);
+ int bandwidth = atoi(optarg);
+ cout << " bandwidth per link (MB/sec) = " << bandwidth << endl;
+ g_endpoint_bandwidth = bandwidth;
+ if (bandwidth == 0) {
+ usageInstructions();
+ }
+ break;
+ }
+
+ case 't': {
+ checkArg(c);
+ g_bash_bandwidth_adaptive_threshold = atof(optarg);
+ if ((g_bash_bandwidth_adaptive_threshold > 1.1) || (g_bash_bandwidth_adaptive_threshold < -0.1)) {
+ cerr << "Error: Bandwidth adaptive threshold must be between 0.0 and 1.0" << endl;
+ usageInstructions();
+ }
+
+ break;
+ }
+
+ case 'k': {
+ checkArg(c);
+ g_think_time = atoi(optarg);
+ break;
+ }
+
+ case 'o':
+ checkArg(c);
+ cout << " output file = " << optarg << endl;
+ DEBUG_OUTPUT_FILENAME = strdup( optarg );
+ break;
+
+ case 'z':
+ checkArg(c);
+ trace_filename = string(optarg);
+ cout << " tracefile = " << trace_filename << endl;
+ break;
+
+ case 'n':
+ checkArg(c);
+ cout << " topology = " << string(optarg) << endl;
+ g_NETWORK_TOPOLOGY = strdup(optarg);
+ break;
+
+ default:
+ cerr << "parameter '" << c << "' unknown" << endl;
+ usageInstructions();
+ }
+ }
+
+ if ((trace_filename != "") || (g_tester_length != 0)) {
+ if ((trace_filename != "") && (g_tester_length != 0)) {
+ cerr << "Error: both a run length (-l) and a trace file (-z) have been specified." << endl;
+ usageInstructions();
+ }
+ } else {
+ cerr << "Error: either run length (-l) must be > 0 or a trace file (-z) must be specified." << endl;
+ usageInstructions();
+ }
+}
+
+static void usageInstructions()
+{
+ cerr << endl;
+ cerr << "Options:" << endl;
+
+ // print options
+ int counter = 0;
+ while (long_options[counter].name != NULL) {
+ cerr << " -" << char(long_options[counter].val);
+ if (long_options[counter].has_arg == required_argument) {
+ cerr << " <arg>";
+ }
+ cerr << " --" << long_options[counter].name;
+ if (long_options[counter].has_arg == required_argument) {
+ cerr << " <arg>";
+ }
+ cerr << endl;
+ counter++;
+ }
+
+ cerr << "Option --processors (-p) is required." << endl;
+ cerr << "Either option --length (-l) or --trace_input (-z) must be specified." << endl;
+ cerr << endl;
+ g_debug_ptr->usageInstructions();
+ cerr << endl;
+
+ exit(1);
+}
+
+static void checkArg(char ch)
+{
+ if (optarg == NULL) {
+ cerr << "Error: parameter '" << ch << "' missing required argument" << endl;
+ usageInstructions();
+ }
+}
diff --git a/src/mem/ruby/tester/test_framework.hh b/src/mem/ruby/tester/test_framework.hh
new file mode 100644
index 000000000..5e9e9363b
--- /dev/null
+++ b/src/mem/ruby/tester/test_framework.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.
+ */
+
+/*
+ * $Id$
+ *
+ * Description:
+ *
+ */
+
+#ifndef TESTFRAMEWORK_H
+#define TESTFRAMEWORK_H
+
+#include "mem/ruby/common/Global.hh"
+#include "mem/ruby/interfaces/mf_api.hh"
+
+void tester_main(int argc, char **argv);
+void tester_install_opal( mf_opal_api_t *opal_api, mf_ruby_api_t *ruby_api );
+
+#endif //TESTFRAMEWORK_H