diff options
Diffstat (limited to 'src/mem/ruby/tester')
33 files changed, 1210 insertions, 2546 deletions
diff --git a/src/mem/ruby/tester/BarrierGenerator.cc b/src/mem/ruby/tester/BarrierGenerator.cc deleted file mode 100644 index 9dbcf39fd..000000000 --- a/src/mem/ruby/tester/BarrierGenerator.cc +++ /dev/null @@ -1,333 +0,0 @@ - -/* - * Copyright (c) 1999-2008 Mark D. Hill and David A. Wood - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/* - * $Id: BarrierGenerator.C 1.3 2005/01/19 13:12:35-06:00 mikem@maya.cs.wisc.edu $ - * - */ - -#include "mem/ruby/tester/BarrierGenerator.hh" -#include "mem/ruby/system/Sequencer.hh" -#include "mem/ruby/system/System.hh" -#include "mem/ruby/config/RubyConfig.hh" -#include "mem/ruby/common/SubBlock.hh" -#include "mem/ruby/tester/SyntheticDriver.hh" -#include "mem/protocol/Chip.hh" - -BarrierGenerator::BarrierGenerator(NodeID node, SyntheticDriver& driver) : - m_driver(driver) -{ - m_status = BarrierGeneratorStatus_Thinking; - m_last_transition = 0; - m_node = node; - m_counter = 0; - proc_counter = 0; - m_local_sense = false; - - m_total_think = 0; - m_think_periods = 0; - - g_eventQueue_ptr->scheduleEvent(this, 1+(random() % 200)); -} - -BarrierGenerator::~BarrierGenerator() -{ -} - -void BarrierGenerator::wakeup() -{ - DEBUG_EXPR(TESTER_COMP, MedPrio, m_node); - DEBUG_EXPR(TESTER_COMP, MedPrio, m_status); - - if (m_status == BarrierGeneratorStatus_Thinking) { - m_barrier_done = false; - m_local_sense = !m_local_sense; - m_status = BarrierGeneratorStatus_Test_Pending; - m_last_transition = g_eventQueue_ptr->getTime(); - initiateTest(); // Test - } else if (m_status == BarrierGeneratorStatus_Test_Waiting) { - m_status = BarrierGeneratorStatus_Test_Pending; - m_last_transition = g_eventQueue_ptr->getTime(); - initiateTest(); // Test - } else if (m_status == BarrierGeneratorStatus_Release_Waiting) { - m_status = BarrierGeneratorStatus_Release_Pending; - m_last_transition = g_eventQueue_ptr->getTime(); - initiateRelease(); // Test - } else if (m_status == BarrierGeneratorStatus_StoreBarrierCounter_Waiting) { - m_status = BarrierGeneratorStatus_StoreBarrierCounter_Pending; - m_last_transition = g_eventQueue_ptr->getTime(); - initiateStoreCtr(); - } else if (m_status == BarrierGeneratorStatus_StoreFlag_Waiting) { - m_status = BarrierGeneratorStatus_StoreFlag_Pending; - m_last_transition = g_eventQueue_ptr->getTime(); - initiateStoreFlag(); - } else if (m_status == BarrierGeneratorStatus_Holding) { - m_status = BarrierGeneratorStatus_Release_Pending; - m_last_transition = g_eventQueue_ptr->getTime(); - initiateRelease(); // Release - } else if (m_status == BarrierGeneratorStatus_Before_Swap) { - m_status = BarrierGeneratorStatus_Swap_Pending; - m_last_transition = g_eventQueue_ptr->getTime(); - initiateSwap(); - } else if (m_status == BarrierGeneratorStatus_SpinFlag_Ready) { - m_status = BarrierGeneratorStatus_SpinFlag_Pending; - m_last_transition = g_eventQueue_ptr->getTime(); - initiateLoadFlag(); - } else { - WARN_EXPR(m_status); - ERROR_MSG("Invalid status"); - } -} - -void BarrierGenerator::performCallback(NodeID proc, SubBlock& data) -{ - Address address = data.getAddress(); - assert(proc == m_node); - - DEBUG_EXPR(TESTER_COMP, LowPrio, proc); - DEBUG_EXPR(TESTER_COMP, LowPrio, m_status); - DEBUG_EXPR(TESTER_COMP, LowPrio, address); - DEBUG_EXPR(TESTER_COMP, LowPrio, data); - - if (m_status == BarrierGeneratorStatus_Test_Pending) { - uint8 dat = data.readByte(); - uint8 lock = dat >> 7; - if (lock == 1) { - // Locked - keep spinning - m_status = BarrierGeneratorStatus_Test_Waiting; - m_last_transition = g_eventQueue_ptr->getTime(); - g_eventQueue_ptr->scheduleEvent(this, waitTime()); - } else { - // Unlocked - try the swap - m_driver.recordTestLatency(g_eventQueue_ptr->getTime() - m_last_transition); - m_status = BarrierGeneratorStatus_Before_Swap; - m_last_transition = g_eventQueue_ptr->getTime(); - g_eventQueue_ptr->scheduleEvent(this, waitTime()); - } - } else if (m_status == BarrierGeneratorStatus_Swap_Pending) { - m_driver.recordSwapLatency(g_eventQueue_ptr->getTime() - m_last_transition); - uint8 dat = data.readByte(); - uint8 lock = dat >> 7; - if (lock == 1) { - // We failed to aquire the lock - m_status = BarrierGeneratorStatus_Test_Waiting; - m_last_transition = g_eventQueue_ptr->getTime(); - g_eventQueue_ptr->scheduleEvent(this, waitTime()); - } else { - // We acquired the lock - dat = dat | 0x80; - data.writeByte(dat); - m_status = BarrierGeneratorStatus_StoreBarrierCounter_Waiting; - m_last_transition = g_eventQueue_ptr->getTime(); - DEBUG_MSG(TESTER_COMP, HighPrio, "Acquired"); - DEBUG_EXPR(TESTER_COMP, HighPrio, proc); - DEBUG_EXPR(TESTER_COMP, HighPrio, g_eventQueue_ptr->getTime()); - // g_eventQueue_ptr->scheduleEvent(this, holdTime()); - - g_eventQueue_ptr->scheduleEvent(this, 1); - - // initiateLoadCtr(); - } - } else if (m_status == BarrierGeneratorStatus_StoreBarrierCounter_Pending) { - - // if value == p, reset counter and set local sense flag - uint8 ctr = data.readByte(); - //uint8 sense = ctr >> 4; - ctr = ctr & 0x0F; - - ctr++; - data.writeByte( ctr | 0x80); // store counter and lock - - //cout << m_node << " incremented Barrier_ctr to " << (int)ctr << ", " << data << "\n"; - - if (ctr == (uint8) 16) { - - data.writeByte( 0x0 ); - m_status = BarrierGeneratorStatus_StoreFlag_Waiting; - m_barrier_done = true; - - g_eventQueue_ptr->scheduleEvent(this, 1); - } - else { - - m_status = BarrierGeneratorStatus_Release_Waiting; - g_eventQueue_ptr->scheduleEvent(this, 1); - } - } else if (m_status == BarrierGeneratorStatus_StoreFlag_Pending) { - - // write flag - if (m_local_sense) { - data.writeByte( 0x01 ); - } - else { - data.writeByte( 0x00 ); - } - - m_status = BarrierGeneratorStatus_Release_Waiting; - g_eventQueue_ptr->scheduleEvent(this, 1); - - } else if (m_status == BarrierGeneratorStatus_Release_Pending) { - m_driver.recordReleaseLatency(g_eventQueue_ptr->getTime() - m_last_transition); - // We're releasing the lock - uint8 dat = data.readByte(); - dat = dat & 0x7F; - data.writeByte(dat); - - if (m_barrier_done) { - m_counter++; - proc_counter++; - if (m_counter < g_tester_length) { - m_status = BarrierGeneratorStatus_Thinking; - m_last_transition = g_eventQueue_ptr->getTime(); - g_eventQueue_ptr->scheduleEvent(this, thinkTime()); - } else { - - m_driver.reportDone(proc_counter, m_node); - m_last_transition = g_eventQueue_ptr->getTime(); - } - } - else { - m_status = BarrierGeneratorStatus_SpinFlag_Ready; - m_last_transition = g_eventQueue_ptr->getTime(); - g_eventQueue_ptr->scheduleEvent(this, waitTime()); - } - } else if (m_status == BarrierGeneratorStatus_SpinFlag_Pending) { - - uint8 sense = data.readByte(); - - - if (sense != m_local_sense) { - m_status = BarrierGeneratorStatus_SpinFlag_Ready; - m_last_transition = g_eventQueue_ptr->getTime(); - g_eventQueue_ptr->scheduleEvent(this, waitTime()); - } - else { - m_counter++; - proc_counter++; - if (m_counter < g_tester_length) { - m_status = BarrierGeneratorStatus_Thinking; - m_last_transition = g_eventQueue_ptr->getTime(); - g_eventQueue_ptr->scheduleEvent(this, thinkTime()); - } else { - m_driver.reportDone(proc_counter, m_node); - m_status = BarrierGeneratorStatus_Done; - m_last_transition = g_eventQueue_ptr->getTime(); - } - } - - } else { - WARN_EXPR(m_status); - ERROR_MSG("Invalid status"); - } -} - -int BarrierGenerator::thinkTime() -{ - int ret; - float ratio = g_think_fudge_factor; - - // return 400; - - if (ratio == 0) { - return g_think_time; - } - - int r = random(); - int x = (int) ( (float)g_think_time*ratio*2.0); - int mod = r % x; - - - int rand = ( mod+1 - ((float)g_think_time*ratio) ); - - ret = (g_think_time + rand); - - m_total_think += ret; - m_think_periods++; - - return ret; -} - -int BarrierGenerator::waitTime() const -{ - return g_wait_time; -} - - -void BarrierGenerator::initiateTest() -{ - DEBUG_MSG(TESTER_COMP, MedPrio, "initiating Test"); - sequencer()->makeRequest(CacheMsg(Address(0x40), CacheRequestType_LD, Address(1), AccessModeType_UserMode, 1, PrefetchBit_No, 0, false)); -} - -void BarrierGenerator::initiateSwap() -{ - DEBUG_MSG(TESTER_COMP, MedPrio, "initiating Swap"); - sequencer()->makeRequest(CacheMsg(Address(0x40), CacheRequestType_ATOMIC, Address(2), AccessModeType_UserMode, 1, PrefetchBit_No, 0, false)); -} - -void BarrierGenerator::initiateRelease() -{ - DEBUG_MSG(TESTER_COMP, MedPrio, "initiating Release"); - sequencer()->makeRequest(CacheMsg(Address(0x40), CacheRequestType_ST, Address(3), AccessModeType_UserMode, 1, PrefetchBit_No, 0, false)); -} - -void BarrierGenerator::initiateLoadCtr() -{ - DEBUG_MSG(TESTER_COMP, MedPrio, "initiating load of barrier counter"); - sequencer()->makeRequest(CacheMsg(Address(0x40), CacheRequestType_LD, Address(3), AccessModeType_UserMode, 1, PrefetchBit_No, 0, false)); -} - -void BarrierGenerator::initiateStoreCtr() -{ - DEBUG_MSG(TESTER_COMP, MedPrio, "initiating load of barrier counter"); - sequencer()->makeRequest(CacheMsg(Address(0x40), CacheRequestType_ST, Address(3), AccessModeType_UserMode, 1, PrefetchBit_No, 0, false)); -} - -void BarrierGenerator::initiateStoreFlag() -{ - DEBUG_MSG(TESTER_COMP, MedPrio, "initiating load of barrier counter"); - sequencer()->makeRequest(CacheMsg(Address(0x00), CacheRequestType_ST, Address(3), AccessModeType_UserMode, 1, PrefetchBit_No, 0, false)); -} - -void BarrierGenerator::initiateLoadFlag() -{ - DEBUG_MSG(TESTER_COMP, MedPrio, "initiating load of barrier counter"); - sequencer()->makeRequest(CacheMsg(Address(0x00), CacheRequestType_LD, Address(3), AccessModeType_UserMode, 1, PrefetchBit_No, 0, false)); -} - - -Sequencer* BarrierGenerator::sequencer() const -{ - return g_system_ptr->getChip(m_node/RubyConfig::numberOfProcsPerChip())->getSequencer(m_node%RubyConfig::numberOfProcsPerChip()); -} - -void BarrierGenerator::print(ostream& out) const -{ -} - diff --git a/src/mem/ruby/tester/BarrierGenerator.hh b/src/mem/ruby/tester/BarrierGenerator.hh deleted file mode 100644 index e0fa497da..000000000 --- a/src/mem/ruby/tester/BarrierGenerator.hh +++ /dev/null @@ -1,138 +0,0 @@ - -/* - * Copyright (c) 1999-2008 Mark D. Hill and David A. Wood - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/* - * $Id$ - * - * Description: - * - */ - -#ifndef BARRIERGENERATOR_H -#define BARRIERGENERATOR_H - -#include "mem/ruby/common/Global.hh" -#include "mem/ruby/common/Consumer.hh" -#include "mem/ruby/system/NodeID.hh" -#include "mem/ruby/common/Address.hh" - -class Sequencer; -class SubBlock; -class SyntheticDriver; - - -enum BarrierGeneratorStatus { - BarrierGeneratorStatus_FIRST, - BarrierGeneratorStatus_Thinking = BarrierGeneratorStatus_FIRST, - BarrierGeneratorStatus_Test_Pending, - BarrierGeneratorStatus_Test_Waiting, - BarrierGeneratorStatus_Before_Swap, - BarrierGeneratorStatus_Swap_Pending, - BarrierGeneratorStatus_Holding, - BarrierGeneratorStatus_Release_Pending, - BarrierGeneratorStatus_Release_Waiting, - BarrierGeneratorStatus_StoreFlag_Waiting, - BarrierGeneratorStatus_StoreFlag_Pending, - BarrierGeneratorStatus_Done, - BarrierGeneratorStatus_SpinFlag_Ready, - BarrierGeneratorStatus_SpinFlag_Pending, - BarrierGeneratorStatus_LoadBarrierCounter_Pending, - BarrierGeneratorStatus_StoreBarrierCounter_Pending, - BarrierGeneratorStatus_StoreBarrierCounter_Waiting, - BarrierGeneratorStatus_NUM -}; - - -// UNCOMMENT THIS FOR A SINGLE WORK QUEUE -// static int m_counter; - -class BarrierGenerator : public Consumer { -public: - // Constructors - BarrierGenerator(NodeID node, SyntheticDriver& driver); - - // Destructor - ~BarrierGenerator(); - - // Public Methods - void wakeup(); - void performCallback(NodeID proc, SubBlock& data); - - void print(ostream& out) const; -private: - // Private Methods - int thinkTime() ; - int waitTime() const; - void initiateTest(); - void initiateSwap(); - void initiateRelease(); - void initiateLoadCtr(); - void initiateStoreCtr(); - void initiateLoadFlag(); - void initiateStoreFlag(); - Sequencer* sequencer() const; - - // Private copy constructor and assignment operator - BarrierGenerator(const BarrierGenerator& obj); - BarrierGenerator& operator=(const BarrierGenerator& obj); - - // Data Members (m_ prefix) - SyntheticDriver& m_driver; - NodeID m_node; - BarrierGeneratorStatus m_status; - int proc_counter; - - int m_counter; - - bool m_local_sense; - bool m_barrier_done; - - Time m_last_transition; - Address m_address; - - int m_total_think; - int m_think_periods; -}; - -// Output operator declaration -ostream& operator<<(ostream& out, const BarrierGenerator& obj); - -// ******************* Definitions ******************* - -// Output operator definition -extern inline -ostream& operator<<(ostream& out, const BarrierGenerator& obj) -{ - obj.print(out); - out << flush; - return out; -} - -#endif //REQUESTGENERATOR_H - diff --git a/src/mem/ruby/tester/Check.cc b/src/mem/ruby/tester/Check.cc deleted file mode 100644 index 7896b572a..000000000 --- a/src/mem/ruby/tester/Check.cc +++ /dev/null @@ -1,310 +0,0 @@ - -/* - * Copyright (c) 1999-2008 Mark D. Hill and David A. Wood - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/* - * $Id$ - * - */ - -#include "mem/ruby/tester/Check.hh" -#include "mem/ruby/system/Sequencer.hh" -#include "mem/ruby/system/System.hh" -#include "mem/ruby/common/SubBlock.hh" -#include "mem/protocol/Chip.hh" -#include "mem/packet.hh" - -Check::Check(const Address& address, const Address& pc) -{ - m_status = TesterStatus_Idle; - - pickValue(); - pickInitiatingNode(); - changeAddress(address); - m_pc = pc; - m_access_mode = AccessModeType(random() % AccessModeType_NUM); - m_store_count = 0; -} - -void Check::initiate() -{ - DEBUG_MSG(TESTER_COMP, MedPrio, "initiating"); - DEBUG_EXPR(TESTER_COMP, MedPrio, *this); - - // current CMP protocol doesn't support prefetches - if (!Protocol::m_CMP && (random() & 0xf) == 0) { // 1 in 16 chance - initiatePrefetch(); // Prefetch from random processor - } - - if(m_status == TesterStatus_Idle) { - initiateAction(); - } else if(m_status == TesterStatus_Ready) { - initiateCheck(); - } else { - // Pending - do nothing - DEBUG_MSG(TESTER_COMP, MedPrio, "initiating action/check - failed: action/check is pending\n"); - } -} - -void Check::initiatePrefetch(Sequencer* targetSequencer_ptr) -{ - DEBUG_MSG(TESTER_COMP, MedPrio, "initiating prefetch"); - - CacheRequestType type; - if ((random() & 0x7) != 0) { // 1 in 8 chance - if ((random() & 0x1) == 0) { // 50% chance - type = CacheRequestType_LD; - } else { - type = CacheRequestType_IFETCH; - } - } else { - type = CacheRequestType_ST; - } - - Addr data_addr = m_address.getAddress(); - Addr pc_addr = m_pc.getAddress(); - Request request(0, data_addr, 0, Flags<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 deleted file mode 100644 index 8f08b3f40..000000000 --- a/src/mem/ruby/tester/Check.hh +++ /dev/null @@ -1,107 +0,0 @@ - -/* - * Copyright (c) 1999-2008 Mark D. Hill and David A. Wood - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/* - * $Id$ - * - * Description: - * - */ - -#ifndef CHECK_H -#define CHECK_H - -#include "mem/ruby/common/Global.hh" -#include "mem/ruby/common/Address.hh" -#include "mem/ruby/system/NodeID.hh" -#include "mem/protocol/TesterStatus.hh" -#include "mem/protocol/AccessModeType.hh" -class Sequencer; -class SubBlock; - -const int CHECK_SIZE_BITS = 2; -const int CHECK_SIZE = (1<<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 deleted file mode 100644 index b8e57a646..000000000 --- a/src/mem/ruby/tester/CheckTable.cc +++ /dev/null @@ -1,128 +0,0 @@ - -/* - * Copyright (c) 1999-2008 Mark D. Hill and David A. Wood - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/* - * $Id$ - * - */ - -#include "mem/ruby/tester/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/DetermGETXGenerator.cc b/src/mem/ruby/tester/DetermGETXGenerator.cc index e4d8addd2..6692fb80c 100644 --- a/src/mem/ruby/tester/DetermGETXGenerator.cc +++ b/src/mem/ruby/tester/DetermGETXGenerator.cc @@ -37,26 +37,23 @@ #include "mem/ruby/tester/DetermGETXGenerator.hh" #include "mem/protocol/DetermGETXGeneratorStatus.hh" -#include "mem/protocol/LockStatus.hh" -#include "mem/ruby/system/Sequencer.hh" -#include "mem/ruby/system/System.hh" -#include "mem/ruby/config/RubyConfig.hh" -#include "mem/ruby/common/SubBlock.hh" #include "mem/ruby/tester/DeterministicDriver.hh" -#include "mem/protocol/Chip.hh" -#include "mem/packet.hh" +#include "mem/ruby/tester/Global_Tester.hh" +#include "mem/ruby/tester/SpecifiedGenerator.hh" +//#include "DMAController.hh" +#include "mem/ruby/libruby.hh" -DetermGETXGenerator::DetermGETXGenerator(NodeID node, DeterministicDriver& driver) : - m_driver(driver) + +DetermGETXGenerator::DetermGETXGenerator(NodeID node, DeterministicDriver * driver) { m_status = DetermGETXGeneratorStatus_Thinking; m_last_transition = 0; m_node = node; m_address = Address(9999); // initialize to null value m_counter = 0; - + parent_driver = driver; // don't know exactly when this node needs to request so just guess randomly - g_eventQueue_ptr->scheduleEvent(this, 1+(random() % 200)); + parent_driver->eventQueue->scheduleEvent(this, 1+(random() % 200)); } DetermGETXGenerator::~DetermGETXGenerator() @@ -70,13 +67,13 @@ void DetermGETXGenerator::wakeup() // determine if this node is next for the GETX round robin request if (m_status == DetermGETXGeneratorStatus_Thinking) { - if (m_driver.isStoreReady(m_node)) { + if (parent_driver->isStoreReady(m_node)) { pickAddress(); m_status = DetermGETXGeneratorStatus_Store_Pending; // Store Pending - m_last_transition = g_eventQueue_ptr->getTime(); + m_last_transition = parent_driver->eventQueue->getTime(); initiateStore(); // GETX } else { // I'll check again later - g_eventQueue_ptr->scheduleEvent(this, thinkTime()); + parent_driver->eventQueue->scheduleEvent(this, thinkTime()); } } else { WARN_EXPR(m_status); @@ -85,31 +82,28 @@ void DetermGETXGenerator::wakeup() } -void DetermGETXGenerator::performCallback(NodeID proc, SubBlock& data) +void DetermGETXGenerator::performCallback(NodeID proc, Address address) { - Address address = data.getAddress(); assert(proc == m_node); assert(address == m_address); DEBUG_EXPR(TESTER_COMP, LowPrio, proc); DEBUG_EXPR(TESTER_COMP, LowPrio, m_status); DEBUG_EXPR(TESTER_COMP, LowPrio, address); - DEBUG_EXPR(TESTER_COMP, LowPrio, data); if (m_status == DetermGETXGeneratorStatus_Store_Pending) { - m_driver.recordStoreLatency(g_eventQueue_ptr->getTime() - m_last_transition); - data.writeByte(m_node); - m_driver.storeCompleted(m_node, data.getAddress()); // advance the store queue + parent_driver->recordStoreLatency(parent_driver->eventQueue->getTime() - m_last_transition); + parent_driver->storeCompleted(m_node, address); // advance the store queue m_counter++; - if (m_counter < g_tester_length) { + if (m_counter < parent_driver->m_tester_length) { m_status = DetermGETXGeneratorStatus_Thinking; - m_last_transition = g_eventQueue_ptr->getTime(); - g_eventQueue_ptr->scheduleEvent(this, waitTime()); + m_last_transition = parent_driver->eventQueue->getTime(); + parent_driver->eventQueue->scheduleEvent(this, waitTime()); } else { - m_driver.reportDone(); + parent_driver->reportDone(); m_status = DetermGETXGeneratorStatus_Done; - m_last_transition = g_eventQueue_ptr->getTime(); + m_last_transition = parent_driver->eventQueue->getTime(); } } else { @@ -120,38 +114,40 @@ void DetermGETXGenerator::performCallback(NodeID proc, SubBlock& data) int DetermGETXGenerator::thinkTime() const { - return g_think_time; + return parent_driver->m_think_time; } int DetermGETXGenerator::waitTime() const { - return g_wait_time; + return parent_driver->m_wait_time; } void DetermGETXGenerator::pickAddress() { assert(m_status == DetermGETXGeneratorStatus_Thinking); - m_address = m_driver.getNextStoreAddr(m_node); + m_address = parent_driver->getNextStoreAddr(m_node); } void DetermGETXGenerator::initiateStore() { DEBUG_MSG(TESTER_COMP, MedPrio, "initiating Store"); - Addr data_addr = m_address.getAddress(); - Request request(0, data_addr, 1, Flags<unsigned int>(), 3, 0, 0); - MemCmd::Command command; - command = MemCmd::WriteReq; + uint8_t *write_data = new uint8_t[64]; + for(int i=0; i < 64; i++) { + write_data[i] = m_node; + } + + char name [] = "Sequencer_"; + char port_name [13]; + sprintf(port_name, "%s%d", name, m_node); - Packet pkt(&request, command, 0); // TODO -- make dest a real NodeID + int64_t request_id = libruby_issue_request(libruby_get_port_by_name(port_name), RubyRequest(m_address.getAddress(), write_data, 64, 0, RubyRequestType_ST, RubyAccessMode_Supervisor)); - sequencer()->makeRequest(&pkt); -} + // delete [] write_data; -Sequencer* DetermGETXGenerator::sequencer() const -{ - return g_system_ptr->getChip(m_node/RubyConfig::numberOfProcsPerChip())->getSequencer(m_node%RubyConfig::numberOfProcsPerChip()); + ASSERT(parent_driver->requests.find(request_id) == parent_driver->requests.end()); + parent_driver->requests.insert(make_pair(request_id, make_pair(m_node, m_address))); } void DetermGETXGenerator::print(ostream& out) const diff --git a/src/mem/ruby/tester/DetermGETXGenerator.hh b/src/mem/ruby/tester/DetermGETXGenerator.hh index 1f5b67653..82e616e4b 100644 --- a/src/mem/ruby/tester/DetermGETXGenerator.hh +++ b/src/mem/ruby/tester/DetermGETXGenerator.hh @@ -40,28 +40,26 @@ #ifndef DETERMGETXGENERATOR_H #define DETERMGETXGENERATOR_H -#include "mem/ruby/common/Global.hh" +#include "mem/ruby/tester/Global_Tester.hh" #include "mem/ruby/common/Consumer.hh" #include "mem/protocol/DetermGETXGeneratorStatus.hh" -#include "mem/ruby/system/NodeID.hh" -#include "mem/ruby/common/Address.hh" +#include "Address_Tester.hh" #include "mem/ruby/tester/SpecifiedGenerator.hh" -class Sequencer; -class SubBlock; class DeterministicDriver; +class DMAController; class DetermGETXGenerator : public SpecifiedGenerator { public: // Constructors - DetermGETXGenerator(NodeID node, DeterministicDriver& driver); + DetermGETXGenerator(NodeID node, DeterministicDriver * driver); // Destructor ~DetermGETXGenerator(); // Public Methods void wakeup(); - void performCallback(NodeID proc, SubBlock& data); + void performCallback(NodeID proc, Address address); void print(ostream& out) const; private: @@ -69,20 +67,21 @@ private: int thinkTime() const; int waitTime() const; void initiateStore(); + void initiateDMA(); void pickAddress(); - Sequencer* sequencer() const; + DMAController* dma() const; // copy constructor and assignment operator DetermGETXGenerator(const DetermGETXGenerator& obj); DetermGETXGenerator& operator=(const DetermGETXGenerator& obj); + DeterministicDriver * parent_driver; // Data Members (m_ prefix) DetermGETXGeneratorStatus m_status; int m_counter; Address m_address; NodeID m_node; - DeterministicDriver& m_driver; Time m_last_transition; }; diff --git a/src/mem/ruby/tester/DetermInvGenerator.cc b/src/mem/ruby/tester/DetermInvGenerator.cc index bafaa18ae..eebe18057 100644 --- a/src/mem/ruby/tester/DetermInvGenerator.cc +++ b/src/mem/ruby/tester/DetermInvGenerator.cc @@ -38,13 +38,10 @@ #include "mem/ruby/tester/DetermInvGenerator.hh" #include "mem/protocol/DetermInvGeneratorStatus.hh" -#include "mem/protocol/LockStatus.hh" -#include "mem/ruby/system/Sequencer.hh" -#include "mem/ruby/system/System.hh" -#include "mem/ruby/config/RubyConfig.hh" -#include "mem/ruby/common/SubBlock.hh" #include "mem/ruby/tester/DeterministicDriver.hh" -#include "mem/protocol/Chip.hh" +#include "mem/ruby/tester/Global_Tester.hh" +//#include "DMAController.hh" +#include "mem/ruby/libruby.hh" DetermInvGenerator::DetermInvGenerator(NodeID node, DeterministicDriver& driver) : m_driver(driver) @@ -54,9 +51,8 @@ DetermInvGenerator::DetermInvGenerator(NodeID node, DeterministicDriver& driver) m_node = node; m_address = Address(9999); // initiate to a NULL value m_counter = 0; - // don't know exactly when this node needs to request so just guess randomly - g_eventQueue_ptr->scheduleEvent(this, 1+(random() % 200)); + m_driver.eventQueue->scheduleEvent(this, 1+(random() % 200)); } DetermInvGenerator::~DetermInvGenerator() @@ -74,23 +70,23 @@ void DetermInvGenerator::wakeup() if (m_driver.isLoadReady(m_node) && m_counter == m_driver.getStoresCompleted()) { pickLoadAddress(); m_status = DetermInvGeneratorStatus_Load_Pending; // Load Pending - m_last_transition = g_eventQueue_ptr->getTime(); + m_last_transition = m_driver.eventQueue->getTime(); initiateLoad(); // GETS } else { // I'll check again later - g_eventQueue_ptr->scheduleEvent(this, thinkTime()); + m_driver.eventQueue->scheduleEvent(this, thinkTime()); } } else if (m_status == DetermInvGeneratorStatus_Load_Complete) { if (m_driver.isStoreReady(m_node, m_address)) { // do a store in this transaction or start the next one if (m_driver.isLoadReady((0), m_address)) { // everyone is in S for this address i.e. back to node 0 m_status = DetermInvGeneratorStatus_Store_Pending; - m_last_transition = g_eventQueue_ptr->getTime(); + m_last_transition = m_driver.eventQueue->getTime(); initiateStore(); // GETX } else { // I'm next, I just have to wait for all loads to complete - g_eventQueue_ptr->scheduleEvent(this, thinkTime()); + m_driver.eventQueue->scheduleEvent(this, thinkTime()); } } else { // I'm not next to store, go back to thinking m_status = DetermInvGeneratorStatus_Thinking; - g_eventQueue_ptr->scheduleEvent(this, thinkTime()); + m_driver.eventQueue->scheduleEvent(this, thinkTime()); } } else { WARN_EXPR(m_status); @@ -99,48 +95,48 @@ void DetermInvGenerator::wakeup() } -void DetermInvGenerator::performCallback(NodeID proc, SubBlock& data) +void DetermInvGenerator::performCallback(NodeID proc, Address address) { - Address address = data.getAddress(); assert(proc == m_node); assert(address == m_address); DEBUG_EXPR(TESTER_COMP, LowPrio, proc); DEBUG_EXPR(TESTER_COMP, LowPrio, m_status); DEBUG_EXPR(TESTER_COMP, LowPrio, address); - DEBUG_EXPR(TESTER_COMP, LowPrio, data); if (m_status == DetermInvGeneratorStatus_Load_Pending) { - m_driver.recordLoadLatency(g_eventQueue_ptr->getTime() - m_last_transition); - m_driver.loadCompleted(m_node, data.getAddress()); + m_driver.recordLoadLatency(m_driver.eventQueue->getTime() - m_last_transition); + //NodeID firstByte = data.readByte(); // dummy read + + m_driver.loadCompleted(m_node, address); if (!m_driver.isStoreReady(m_node, m_address)) { // if we don't have to store, we are done for this transaction m_counter++; } - if (m_counter < g_tester_length) { + if (m_counter < m_driver.m_tester_length) { m_status = DetermInvGeneratorStatus_Load_Complete; - m_last_transition = g_eventQueue_ptr->getTime(); - g_eventQueue_ptr->scheduleEvent(this, waitTime()); + m_last_transition = m_driver.eventQueue->getTime(); + m_driver.eventQueue->scheduleEvent(this, waitTime()); } else { m_driver.reportDone(); m_status = DetermInvGeneratorStatus_Done; - m_last_transition = g_eventQueue_ptr->getTime(); + m_last_transition = m_driver.eventQueue->getTime(); } } else if (m_status == DetermInvGeneratorStatus_Store_Pending) { - m_driver.recordStoreLatency(g_eventQueue_ptr->getTime() - m_last_transition); - data.writeByte(m_node); - m_driver.storeCompleted(m_node, data.getAddress()); // advance the store queue + m_driver.recordStoreLatency(m_driver.eventQueue->getTime() - m_last_transition); + //data.writeByte(m_node); + m_driver.storeCompleted(m_node, address); // advance the store queue m_counter++; - if (m_counter < g_tester_length) { + if (m_counter < m_driver.m_tester_length) { m_status = DetermInvGeneratorStatus_Thinking; - m_last_transition = g_eventQueue_ptr->getTime(); - g_eventQueue_ptr->scheduleEvent(this, waitTime()); + m_last_transition = m_driver.eventQueue->getTime(); + m_driver.eventQueue->scheduleEvent(this, waitTime()); } else { m_driver.reportDone(); m_status = DetermInvGeneratorStatus_Done; - m_last_transition = g_eventQueue_ptr->getTime(); + m_last_transition = m_driver.eventQueue->getTime(); } } else { WARN_EXPR(m_status); @@ -150,23 +146,22 @@ void DetermInvGenerator::performCallback(NodeID proc, SubBlock& data) DEBUG_EXPR(TESTER_COMP, LowPrio, proc); DEBUG_EXPR(TESTER_COMP, LowPrio, m_status); DEBUG_EXPR(TESTER_COMP, LowPrio, address); - DEBUG_EXPR(TESTER_COMP, LowPrio, data); } int DetermInvGenerator::thinkTime() const { - return g_think_time; + return m_driver.m_think_time; } int DetermInvGenerator::waitTime() const { - return g_wait_time; + return m_driver.m_wait_time; } int DetermInvGenerator::holdTime() const { - return g_hold_time; + assert(0); } void DetermInvGenerator::pickLoadAddress() @@ -179,35 +174,42 @@ void DetermInvGenerator::pickLoadAddress() void DetermInvGenerator::initiateLoad() { DEBUG_MSG(TESTER_COMP, MedPrio, "initiating Load"); + // sequencer()->makeRequest(CacheMsg(m_address, m_address, CacheRequestType_LD, Address(1), AccessModeType_UserMode, 1, PrefetchBit_No, Address(0), 0 /* only 1 SMT thread */)); + uint8_t * read_data = new uint8_t[64]; - Addr data_addr = m_address.getAddress(); - Request request(0, data_addr, 1, Flags<unsigned int>(), 1, 0, 0); - MemCmd::Command command; - command = MemCmd::ReadReq; + char name [] = "Sequencer_"; + char port_name [13]; + sprintf(port_name, "%s%d", name, m_node); - Packet pkt(&request, command, 0); // TODO -- make dest a real NodeID + int64_t request_id = libruby_issue_request(libruby_get_port_by_name(port_name), RubyRequest(m_address.getAddress(), read_data, 64, 0, RubyRequestType_LD, RubyAccessMode_Supervisor)); - sequencer()->makeRequest(&pkt); + //delete [] read_data; + + ASSERT(m_driver.requests.find(request_id) == m_driver.requests.end()); + m_driver.requests.insert(make_pair(request_id, make_pair(m_node, m_address))); } void DetermInvGenerator::initiateStore() { DEBUG_MSG(TESTER_COMP, MedPrio, "initiating Store"); + // sequencer()->makeRequest(CacheMsg(m_address, m_address, CacheRequestType_ST, Address(3), AccessModeType_UserMode, 1, PrefetchBit_No, Address(0), 0 /* only 1 SMT thread */)); + uint8_t *write_data = new uint8_t[64]; + for(int i=0; i < 64; i++) { + write_data[i] = m_node; + } - Addr data_addr = m_address.getAddress(); - Request request(0, data_addr, 1, Flags<unsigned int>(), 3, 0, 0); - MemCmd::Command command; - command = MemCmd::WriteReq; + char name [] = "Sequencer_"; + char port_name [13]; + sprintf(port_name, "%s%d", name, m_node); - Packet pkt(&request, command, 0); // TODO -- make dest a real NodeID + int64_t request_id = libruby_issue_request(libruby_get_port_by_name(port_name), RubyRequest(m_address.getAddress(), write_data, 64, 0, RubyRequestType_ST, RubyAccessMode_Supervisor)); - sequencer()->makeRequest(&pkt); -} + //delete [] write_data; + + ASSERT(m_driver.requests.find(request_id) == m_driver.requests.end()); + m_driver.requests.insert(make_pair(request_id, make_pair(m_node, m_address))); -Sequencer* DetermInvGenerator::sequencer() const -{ - return g_system_ptr->getChip(m_node/RubyConfig::numberOfProcsPerChip())->getSequencer(m_node%RubyConfig::numberOfProcsPerChip()); } void DetermInvGenerator::print(ostream& out) const diff --git a/src/mem/ruby/tester/DetermInvGenerator.hh b/src/mem/ruby/tester/DetermInvGenerator.hh index 4f0712fbe..6127c3af4 100644 --- a/src/mem/ruby/tester/DetermInvGenerator.hh +++ b/src/mem/ruby/tester/DetermInvGenerator.hh @@ -41,15 +41,12 @@ #ifndef DETERMINVGENERATOR_H #define DETERMINVGENERATOR_H -#include "mem/ruby/common/Global.hh" +#include "mem/ruby/tester/Global_Tester.hh" #include "mem/ruby/common/Consumer.hh" #include "mem/protocol/DetermInvGeneratorStatus.hh" -#include "mem/ruby/system/NodeID.hh" -#include "mem/ruby/common/Address.hh" +#include "Address_Tester.hh" #include "mem/ruby/tester/SpecifiedGenerator.hh" -class Sequencer; -class SubBlock; class DeterministicDriver; class DetermInvGenerator : public SpecifiedGenerator { @@ -62,7 +59,7 @@ public: // Public Methods void wakeup(); - void performCallback(NodeID proc, SubBlock& data); + void performCallback(NodeID proc, Address address); void print(ostream& out) const; private: @@ -75,8 +72,6 @@ private: void pickLoadAddress(); void pickStoreAddress(); - Sequencer* sequencer() const; - // copy constructor and assignment operator DetermInvGenerator(const DetermInvGenerator& obj); DetermInvGenerator& operator=(const DetermInvGenerator& obj); diff --git a/src/mem/ruby/tester/DetermSeriesGETSGenerator.cc b/src/mem/ruby/tester/DetermSeriesGETSGenerator.cc index 5adc7aa5c..38688f10d 100644 --- a/src/mem/ruby/tester/DetermSeriesGETSGenerator.cc +++ b/src/mem/ruby/tester/DetermSeriesGETSGenerator.cc @@ -34,13 +34,7 @@ #include "mem/ruby/tester/DetermSeriesGETSGenerator.hh" #include "mem/protocol/DetermSeriesGETSGeneratorStatus.hh" -#include "mem/protocol/LockStatus.hh" -#include "mem/ruby/system/Sequencer.hh" -#include "mem/ruby/system/System.hh" -#include "mem/ruby/config/RubyConfig.hh" -#include "mem/ruby/common/SubBlock.hh" #include "mem/ruby/tester/DeterministicDriver.hh" -#include "mem/protocol/Chip.hh" DetermSeriesGETSGenerator::DetermSeriesGETSGenerator(NodeID node, DeterministicDriver& driver) : m_driver(driver) @@ -51,8 +45,9 @@ DetermSeriesGETSGenerator::DetermSeriesGETSGenerator(NodeID node, DeterministicD m_address = Address(9999); // initialize to null value m_counter = 0; + // don't know exactly when this node needs to request so just guess randomly - g_eventQueue_ptr->scheduleEvent(this, 1+(random() % 200)); + m_driver.eventQueue->scheduleEvent(this, 1+(random() % 200)); } DetermSeriesGETSGenerator::~DetermSeriesGETSGenerator() @@ -69,10 +64,10 @@ void DetermSeriesGETSGenerator::wakeup() if (m_driver.isLoadReady(m_node)) { pickAddress(); m_status = DetermSeriesGETSGeneratorStatus_Load_Pending; // Load Pending - m_last_transition = g_eventQueue_ptr->getTime(); + m_last_transition = m_driver.eventQueue->getTime(); initiateLoad(); // SeriesGETS } else { // I'll check again later - g_eventQueue_ptr->scheduleEvent(this, thinkTime()); + m_driver.eventQueue->scheduleEvent(this, thinkTime()); } } else { WARN_EXPR(m_status); @@ -81,32 +76,30 @@ void DetermSeriesGETSGenerator::wakeup() } -void DetermSeriesGETSGenerator::performCallback(NodeID proc, SubBlock& data) +void DetermSeriesGETSGenerator::performCallback(NodeID proc, Address address) { - Address address = data.getAddress(); assert(proc == m_node); assert(address == m_address); DEBUG_EXPR(TESTER_COMP, LowPrio, proc); DEBUG_EXPR(TESTER_COMP, LowPrio, m_status); DEBUG_EXPR(TESTER_COMP, LowPrio, address); - DEBUG_EXPR(TESTER_COMP, LowPrio, data); if (m_status == DetermSeriesGETSGeneratorStatus_Load_Pending) { - m_driver.recordLoadLatency(g_eventQueue_ptr->getTime() - m_last_transition); - data.writeByte(m_node); - m_driver.loadCompleted(m_node, data.getAddress()); // advance the load queue + m_driver.recordLoadLatency(m_driver.eventQueue->getTime() - m_last_transition); + //data.writeByte(m_node); + m_driver.loadCompleted(m_node, address); // advance the load queue m_counter++; // do we still have more requests to complete before the next proc starts? - if (m_counter < g_tester_length*g_NUM_COMPLETIONS_BEFORE_PASS) { + if (m_counter < m_driver.m_tester_length*m_driver.m_numCompletionsPerNode) { m_status = DetermSeriesGETSGeneratorStatus_Thinking; - m_last_transition = g_eventQueue_ptr->getTime(); - g_eventQueue_ptr->scheduleEvent(this, waitTime()); + m_last_transition = m_driver.eventQueue->getTime(); + m_driver.eventQueue->scheduleEvent(this, waitTime()); } else { m_driver.reportDone(); m_status = DetermSeriesGETSGeneratorStatus_Done; - m_last_transition = g_eventQueue_ptr->getTime(); + m_last_transition = m_driver.eventQueue->getTime(); } } else { @@ -117,12 +110,12 @@ void DetermSeriesGETSGenerator::performCallback(NodeID proc, SubBlock& data) int DetermSeriesGETSGenerator::thinkTime() const { - return g_think_time; + return m_driver.m_think_time; } int DetermSeriesGETSGenerator::waitTime() const { - return g_wait_time; + return m_driver.m_wait_time; } void DetermSeriesGETSGenerator::pickAddress() @@ -135,21 +128,20 @@ void DetermSeriesGETSGenerator::pickAddress() void DetermSeriesGETSGenerator::initiateLoad() { DEBUG_MSG(TESTER_COMP, MedPrio, "initiating Load"); + //sequencer()->makeRequest(CacheMsg(m_address, m_address, CacheRequestType_IFETCH, Address(3), AccessModeType_UserMode, 1, PrefetchBit_No, Address(0), 0 /* only 1 SMT thread */)); - Addr data_addr = m_address.getAddress(); - Request request(0, data_addr, 1, Flags<unsigned int>(), 3, 0, 0); - MemCmd::Command command; - command = MemCmd::ReadReq; - request.setFlags(Request::INST_FETCH); + uint8_t *read_data = new uint8_t[64]; - Packet pkt(&request, command, 0); // TODO -- make dest a real NodeID + char name [] = "Sequencer_"; + char port_name [13]; + sprintf(port_name, "%s%d", name, m_node); - sequencer()->makeRequest(&pkt); -} + int64_t request_id = libruby_issue_request(libruby_get_port_by_name(port_name), RubyRequest(m_address.getAddress(), read_data, 64, 0, RubyRequestType_LD, RubyAccessMode_Supervisor)); -Sequencer* DetermSeriesGETSGenerator::sequencer() const -{ - return g_system_ptr->getChip(m_node/RubyConfig::numberOfProcsPerChip())->getSequencer(m_node%RubyConfig::numberOfProcsPerChip()); + //delete [] read_data; + + ASSERT(m_driver.requests.find(request_id) == m_driver.requests.end()); + m_driver.requests.insert(make_pair(request_id, make_pair(m_node, m_address))); } void DetermSeriesGETSGenerator::print(ostream& out) const diff --git a/src/mem/ruby/tester/DetermSeriesGETSGenerator.hh b/src/mem/ruby/tester/DetermSeriesGETSGenerator.hh index 1e44dc3bc..225e45a11 100644 --- a/src/mem/ruby/tester/DetermSeriesGETSGenerator.hh +++ b/src/mem/ruby/tester/DetermSeriesGETSGenerator.hh @@ -42,15 +42,12 @@ #ifndef DETERMSERIESGETSGENERATOR_H #define DETERMSERIESGETSGENERATOR_H -#include "mem/ruby/common/Global.hh" +#include "mem/ruby/tester/Global_Tester.hh" #include "mem/ruby/common/Consumer.hh" #include "mem/protocol/DetermSeriesGETSGeneratorStatus.hh" -#include "mem/ruby/system/NodeID.hh" -#include "mem/ruby/common/Address.hh" +#include "Address_Tester.hh" #include "mem/ruby/tester/SpecifiedGenerator.hh" -class Sequencer; -class SubBlock; class DeterministicDriver; class DetermSeriesGETSGenerator : public SpecifiedGenerator { @@ -63,7 +60,7 @@ public: // Public Methods void wakeup(); - void performCallback(NodeID proc, SubBlock& data); + void performCallback(NodeID proc, Address address); void print(ostream& out) const; private: @@ -73,8 +70,6 @@ private: void initiateLoad(); void pickAddress(); - Sequencer* sequencer() const; - // copy constructor and assignment operator DetermSeriesGETSGenerator(const DetermSeriesGETSGenerator& obj); DetermSeriesGETSGenerator& operator=(const DetermSeriesGETSGenerator& obj); diff --git a/src/mem/ruby/tester/DeterministicDriver.cc b/src/mem/ruby/tester/DeterministicDriver.cc index 762672118..54b5f5e0d 100644 --- a/src/mem/ruby/tester/DeterministicDriver.cc +++ b/src/mem/ruby/tester/DeterministicDriver.cc @@ -32,67 +32,79 @@ * */ -#include "mem/ruby/common/Global.hh" -#include "mem/ruby/system/System.hh" +#include "mem/ruby/tester/Global_Tester.hh" #include "mem/ruby/tester/DeterministicDriver.hh" -#include "mem/ruby/eventqueue/RubyEventQueue.hh" -#include "mem/ruby/tester/SpecifiedGenerator.hh" +#include "mem/ruby/tester/EventQueue_Tester.hh" +//#include "DMAGenerator.hh" #include "mem/ruby/tester/DetermGETXGenerator.hh" -#include "mem/ruby/tester/DetermInvGenerator.hh" -#include "mem/ruby/tester/DetermSeriesGETSGenerator.hh" -#include "mem/ruby/common/SubBlock.hh" -#include "mem/protocol/Chip.hh" -#include "mem/packet.hh" -DeterministicDriver::DeterministicDriver(RubySystem* sys_ptr) +#define DATA_BLOCK_BYTES 64 + +DeterministicDriver::DeterministicDriver(string generator_type, int num_completions, int num_procs, Time g_think_time, Time g_wait_time, int g_tester_length) { + eventQueue = new RubyEventQueue; m_finish_time = 0; m_last_issue = -11; m_done_counter = 0; m_loads_completed = 0; m_stores_completed = 0; - m_numCompletionsPerNode = g_NUM_COMPLETIONS_BEFORE_PASS; + m_numCompletionsPerNode = num_completions; + m_num_procs = num_procs; + m_think_time = g_think_time; + m_wait_time = g_wait_time; + m_tester_length = g_tester_length; + - m_last_progress_vector.setSize(RubyConfig::numberOfProcessors()); + m_last_progress_vector.setSize(num_procs); for (int i=0; i<m_last_progress_vector.size(); i++) { m_last_progress_vector[i] = 0; } - m_load_vector.setSize(g_deterministic_addrs); + m_load_vector.setSize(10); 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); + m_store_vector.setSize(10); 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()); + m_generator_vector.setSize(num_procs); - SpecifiedGeneratorType generator = string_to_SpecifiedGeneratorType(g_SpecifiedGenerator); + int generator = string_to_SpecifiedGeneratorType(generator_type); 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); + m_generator_vector[i] = new DetermGETXGenerator(i, this); break; case SpecifiedGeneratorType_DetermInvGenerator: m_generator_vector[i] = new DetermInvGenerator(i, *this); break; + case SpecifiedGeneratorType_DetermSeriesGETSGenerator: + m_generator_vector[i] = new DetermSeriesGETSGenerator(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); + //m_dma_generator = new DMAGenerator(0, this); } + +void DeterministicDriver::go() +{ + // tick both queues until everyone is done + while (m_done_counter != m_num_procs) { + libruby_tick(1); + eventQueue->triggerEvents(eventQueue->getTime() + 1); + } +} + + DeterministicDriver::~DeterministicDriver() { for (int i=0; i<m_last_progress_vector.size(); i++) { @@ -100,18 +112,27 @@ DeterministicDriver::~DeterministicDriver() } } -void -DeterministicDriver::hitCallback(Packet * pkt) +//void DeterministicDriver::dmaHitCallback() +//{ +// m_dma_generator->performCallback(); +//} + +void DeterministicDriver::wakeup() { + assert(0); + // this shouldn't be called as we are not scheduling the driver ever +} + +void DeterministicDriver::hitCallback(int64_t request_id) { - NodeID proc = pkt->req->contextId(); - SubBlock data(Address(pkt->getAddr()), pkt->req->getSize()); - if (pkt->hasData()) { - for (int i = 0; i < pkt->req->getSize(); i++) { - data.setByte(i, *(pkt->getPtr<uint8>()+i)); - } - } - m_generator_vector[proc]->performCallback(proc, data); - m_last_progress_vector[proc] = g_eventQueue_ptr->getTime(); + ASSERT(requests.find(request_id) != requests.end()); + int proc = requests[request_id].first; + Address address = requests[request_id].second; + + m_generator_vector[proc]->performCallback(proc, address); + + m_last_progress_vector[proc] = eventQueue->getTime(); + + requests.erase(request_id); } bool DeterministicDriver::isStoreReady(NodeID node) @@ -121,6 +142,8 @@ bool DeterministicDriver::isStoreReady(NodeID node) bool DeterministicDriver::isStoreReady(NodeID node, Address addr) { + int addr_number = addr.getAddress()/DATA_BLOCK_BYTES; + return isAddrReady(node, m_store_vector, addr); } @@ -138,25 +161,26 @@ bool DeterministicDriver::isLoadReady(NodeID node, Address addr) bool DeterministicDriver::isAddrReady(NodeID node, Vector<NodeID> addr_vector) { for (int i=0; i<addr_vector.size(); i++) { - if (((addr_vector[i]+1)%RubyConfig::numberOfProcessors() == node) && + if (((addr_vector[i]+1)%m_num_procs == node) && (m_loads_completed+m_stores_completed >= m_numCompletionsPerNode*node) && // is this node next - (g_eventQueue_ptr->getTime() >= m_last_issue + 10)) { // controll rate of requests + (eventQueue->getTime() >= m_last_issue + 10)) { // controll rate of requests return true; } } + 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(); + int addr_number = addr.getAddress()/DATA_BLOCK_BYTES; ASSERT ((addr_number >= 0) && (addr_number < addr_vector.size())); - if (((addr_vector[addr_number]+1)%RubyConfig::numberOfProcessors() == node) && + if (((addr_vector[addr_number]+1)%m_num_procs == node) && (m_loads_completed+m_stores_completed >= m_numCompletionsPerNode*node) && // is this node next - (g_eventQueue_ptr->getTime() >= m_last_issue + 10)) { // controll rate of requests + (eventQueue->getTime() >= m_last_issue + 10)) { // controll rate of requests return true; } else { return false; @@ -178,7 +202,7 @@ void DeterministicDriver::storeCompleted(NodeID node, Address addr) void DeterministicDriver::setNextAddr(NodeID node, Address addr, Vector<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(); + int addr_number = addr.getAddress()/DATA_BLOCK_BYTES; addr_vector[addr_number] = node; } @@ -204,17 +228,16 @@ Address DeterministicDriver::getNextAddr(NodeID node, Vector<NodeID> addr_vector 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) { + if ((addr_vector[addr_number] != 1) && ((addr_vector[addr_number]+1)%m_num_procs) == node) { // One addr per cache line - addr.setAddress(addr_number * RubyConfig::dataBlockBytes()); + addr.setAddress(addr_number * DATA_BLOCK_BYTES); } } - m_last_issue = g_eventQueue_ptr->getTime(); + m_last_issue = eventQueue->getTime(); return addr; } @@ -223,9 +246,9 @@ Address DeterministicDriver::getNextAddr(NodeID node, Vector<NodeID> addr_vector void DeterministicDriver::reportDone() { m_done_counter++; - if ((m_done_counter == RubyConfig::numberOfProcessors())) { - //|| (m_done_counter == g_tester_length)) { - m_finish_time = g_eventQueue_ptr->getTime(); + if ((m_done_counter == m_num_procs)) { + m_finish_time = eventQueue->getTime(); + //m_dma_generator->stop(); } } @@ -239,36 +262,6 @@ void DeterministicDriver::recordStoreLatency(Time time) m_store_latency.add(time); } -void DeterministicDriver::wakeup() -{ - // checkForDeadlock(); - if (m_done_counter < RubyConfig::numberOfProcessors()) { - g_eventQueue_ptr->scheduleEvent(this, g_DEADLOCK_THRESHOLD); - } -} - -void DeterministicDriver::checkForDeadlock() -{ - int size = m_last_progress_vector.size(); - Time current_time = g_eventQueue_ptr->getTime(); - for (int processor=0; processor<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; diff --git a/src/mem/ruby/tester/DeterministicDriver.hh b/src/mem/ruby/tester/DeterministicDriver.hh index 710da7922..288ad5a15 100644 --- a/src/mem/ruby/tester/DeterministicDriver.hh +++ b/src/mem/ruby/tester/DeterministicDriver.hh @@ -36,25 +36,35 @@ #ifndef DETERMINISTICDRIVER_H #define DETERMINISTICDRIVER_H - -#include "mem/ruby/common/Global.hh" -#include "mem/ruby/common/Driver.hh" -#include "mem/ruby/common/Histogram.hh" -#include "mem/protocol/CacheRequestType.hh" - -class RubySystem; -class SpecifiedGenerator; -class Packet; - -class DeterministicDriver : public Driver, public Consumer { +#include <map> +#include "mem/ruby/tester/Global_Tester.hh" +#include "mem/ruby/common/Histogram.hh" // includes global, but doesn't use anything, so it should be fine +#include "mem/protocol/CacheRequestType.hh" // includes global, but doesn't use anything, so it should be fine +#include "Address_Tester.hh" // we redefined the address +#include "mem/ruby/tester/DetermGETXGenerator.hh" // this is our file +#include "mem/ruby/tester/DetermSeriesGETSGenerator.hh" // this is our file +#include "mem/ruby/tester/DetermInvGenerator.hh" // this is our file +#include "mem/ruby/libruby.hh" +#include "mem/ruby/tester/Driver_Tester.hh" +#include "mem/ruby/common/Consumer.hh" +#include "mem/ruby/tester/EventQueue_Tester.hh" +#include "mem/protocol/SpecifiedGeneratorType.hh" + +//class DMAGenerator; + +class DeterministicDriver : public Driver_Tester, public Consumer { public: + friend class DetermGETXGenerator; + friend class DetermSeriesGETSGenerator; + friend class DetermInvGenerator; // Constructors - DeterministicDriver(RubySystem* sys_ptr); + DeterministicDriver(string generator_type, int num_completions, int num_procs, Time g_think_time, Time g_wait_time, int g_tester_length); // Destructor ~DeterministicDriver(); // Public Methods + void go(); bool isStoreReady(NodeID node); bool isLoadReady(NodeID node); bool isStoreReady(NodeID node, Address addr); @@ -70,37 +80,47 @@ public: void recordLoadLatency(Time time); void recordStoreLatency(Time time); - void hitCallback(Packet* pkt); +// void dmaHitCallback(); + void hitCallback(int64_t request_id); void wakeup(); void printStats(ostream& out) const; void clearStats() {} void printConfig(ostream& out) const {} void print(ostream& out) const; + // Public copy constructor and assignment operator + DeterministicDriver(const DeterministicDriver& obj); + DeterministicDriver& operator=(const DeterministicDriver& obj); + private: // Private Methods - void checkForDeadlock(); Address getNextAddr(NodeID node, Vector<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; + //DMAGenerator* m_dma_generator; Vector<NodeID> m_load_vector; // Processor last to load the addr Vector<NodeID> m_store_vector; // Processor last to store the addr + int last_proc; 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 + + map <int64_t, pair <int, Address> > requests; + Time m_think_time; + Time m_wait_time; + int m_tester_length; + int m_num_procs; + RubyEventQueue * eventQueue; int m_numCompletionsPerNode; Histogram m_load_latency; diff --git a/src/mem/ruby/tester/CheckTable.hh b/src/mem/ruby/tester/Driver_Tester.cc index a7f486315..d29e6f988 100644 --- a/src/mem/ruby/tester/CheckTable.hh +++ b/src/mem/ruby/tester/Driver_Tester.cc @@ -30,64 +30,15 @@ /* * $Id$ * - * Description: + * Description: See Driver_Tester.hh * */ -#ifndef CHECKTABLE_H -#define CHECKTABLE_H +#include "mem/ruby/tester/Driver_Tester.hh" -#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; +Driver_Tester::Driver_Tester() { } -#endif //CHECKTABLE_H +// still need to be defined for subclasses +Driver_Tester::~Driver_Tester() { +} diff --git a/src/mem/ruby/tester/Tester.hh b/src/mem/ruby/tester/Driver_Tester.hh index 7b721e038..77cd4ed3c 100644 --- a/src/mem/ruby/tester/Tester.hh +++ b/src/mem/ruby/tester/Driver_Tester.hh @@ -34,60 +34,49 @@ * */ -#ifndef TESTER_H -#define TESTER_H +#ifndef Driver_Tester_H +#define Driver_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" +#include "mem/ruby/tester/Global_Tester.hh" +#include "mem/ruby/common/Consumer.hh" +#include "mem/ruby/system/NodeID.hh" +#include "Address_Tester.hh" -class RubySystem; - -class Tester : public Driver, public Consumer { +class Driver_Tester { public: // Constructors - Tester(RubySystem* sys_ptr); + Driver_Tester(); // Destructor - ~Tester(); + virtual ~Driver_Tester() = 0; // Public Methods + virtual void get_network_config() {} + virtual void dmaHitCallback() {}; + virtual void hitCallback(int64_t id) = 0; + virtual void go() = 0; + virtual integer_t getInstructionCount(int procID) const { return 1; } + virtual integer_t getCycleCount(int procID) const { return 1; } + virtual void addThreadDependency(int procID, int requestor_thread, int conflict_thread) const { assert(0);} + virtual void printDebug(){} - 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 + virtual void printStats(ostream& out) const = 0; + virtual void clearStats() = 0; - void checkForDeadlock(); + virtual void printConfig(ostream& out) const = 0; - // Private copy constructor and assignment operator - Tester(const Tester& obj); - Tester& operator=(const Tester& obj); + virtual integer_t readPhysicalMemory(int procID, physical_address_t address, + int len ){ ASSERT(0); return 0; } - // Data Members (m_ prefix) + virtual void writePhysicalMemory( int procID, physical_address_t address, + integer_t value, int len ){ ASSERT(0); } - CheckTable m_checkTable; - Vector<Time> m_last_progress_vector; -}; +protected: + // accessible by subclasses -// Output operator declaration -ostream& operator<<(ostream& out, const Tester& obj); - -// ******************* Definitions ******************* +private: + // inaccessible by subclasses -// Output operator definition -extern inline -ostream& operator<<(ostream& out, const Tester& obj) -{ - obj.print(out); - out << flush; - return out; -} +}; -#endif //TESTER_H +#endif //Driver_Tester_H diff --git a/src/mem/ruby/tester/EventQueue_Tester.hh b/src/mem/ruby/tester/EventQueue_Tester.hh new file mode 100644 index 000000000..fe600bb84 --- /dev/null +++ b/src/mem/ruby/tester/EventQueue_Tester.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: The RubyEventQueue class implements an event queue which + * can be trigger events, allowing our simulation to be event driven. + * + * Currently, the only event we support is a Consumer being signaled + * by calling the consumer's wakeup() routine. Adding the event to + * the queue does not require a virtual function call, though calling + * wakeup() is a virtual function call. + * + * The method triggerEvents() is called with a global time. All + * events which are before or at this time are triggered in timestamp + * order. No ordering is enforced for events scheduled to occur at + * the same time. Events scheduled to wakeup the same consumer at the + * same time are combined into a single event. + * + * The method scheduleConsumerWakeup() is called with a global time + * and a consumer pointer. The event queue will call the wakeup() + * method of the consumer at the appropriate time. + * + * This implementation of RubyEventQueue uses a dynamically sized array + * managed as a heap. The algorithms used has O(lg n) for insert and + * O(lg n) for extract minimum element. (Based on chapter 7 of Cormen, + * Leiserson, and Rivest.) The array is dynamically sized and is + * automatically doubled in size when necessary. + * + */ + +#ifndef EVENTQUEUE_H +#define EVENTQUEUE_H + +#include "mem/ruby/tester/Global_Tester.hh" +#include "mem/gems_common/Vector.hh" + +class Consumer; +template <class TYPE> class PrioHeap; +class RubyEventQueueNode; + +class RubyEventQueue { +public: + // Constructors + RubyEventQueue(); + + // Destructor + ~RubyEventQueue(); + + // Public Methods + + Time getTime() const { return m_globalTime; } + void scheduleEvent(Consumer* consumer, Time timeDelta) { scheduleEventAbsolute(consumer, timeDelta + m_globalTime); } + void scheduleEventAbsolute(Consumer* consumer, Time timeAbs); + void triggerEvents(Time t); // called to handle all events <= time t + void triggerAllEvents(); + void print(ostream& out) const; + bool isEmpty() const; + + Time getTimeOfLastRecovery() {return m_timeOfLastRecovery;} + void setTimeOfLastRecovery(Time t) {m_timeOfLastRecovery = t;} + + // Private Methods +private: + // Private copy constructor and assignment operator + void init(); + RubyEventQueue(const RubyEventQueue& obj); + RubyEventQueue& operator=(const RubyEventQueue& obj); + + // Data Members (m_ prefix) + PrioHeap<RubyEventQueueNode>* m_prio_heap_ptr; + Time m_globalTime; + Time m_timeOfLastRecovery; +}; + +// Output operator declaration +inline extern +ostream& operator<<(ostream& out, const RubyEventQueue& obj); + +// ******************* Definitions ******************* + +// Output operator definition +inline extern +ostream& operator<<(ostream& out, const RubyEventQueue& obj) +{ + obj.print(out); + out << flush; + return out; +} + +#endif //EVENTQUEUE_H diff --git a/src/mem/ruby/tester/RequestGenerator.hh b/src/mem/ruby/tester/Global_Tester.hh index 2859eb436..9d622bbf6 100644 --- a/src/mem/ruby/tester/RequestGenerator.hh +++ b/src/mem/ruby/tester/Global_Tester.hh @@ -30,73 +30,45 @@ /* * $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 + * */ + +#ifndef GLOBAL_H +#define GLOBAL_H + +typedef unsigned char uint8; +typedef unsigned int uint32; +typedef unsigned long long uint64; + +typedef signed char int8; +typedef int int32; +typedef long long int64; + +typedef long long integer_t; +typedef unsigned long long uinteger_t; + +typedef int64 Time; +typedef uint64 physical_address_t; +typedef uint64 la_t; +typedef uint64 pa_t; +typedef integer_t simtime_t; +typedef int NodeID; + +#include "mem/ruby/common/TypeDefines.hh" +#include "mem/gems_common/std-includes.hh" +#include "Debug_Tester.hh" + +// simple type declarations +typedef Time LogicalTime; +typedef int64 Index; // what the address bit ripper returns +typedef int word; // one word of a cache line +typedef unsigned int uint; +typedef int SwitchID; +typedef int LinkID; + + +class Debug; +extern Debug * debug_ptr; +class RubyEventQueue; +extern RubyEventQueue * eventQueue; +#endif //GLOBAL_H diff --git a/src/mem/ruby/tester/Instruction.cc b/src/mem/ruby/tester/Instruction.cc deleted file mode 100644 index 1f4d56fc2..000000000 --- a/src/mem/ruby/tester/Instruction.cc +++ /dev/null @@ -1,51 +0,0 @@ -/* - * 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 deleted file mode 100644 index 35791dcba..000000000 --- a/src/mem/ruby/tester/Instruction.hh +++ /dev/null @@ -1,57 +0,0 @@ -/* - * 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.hh 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 index c56557645..dfecfa796 100644 --- a/src/mem/ruby/tester/RaceyDriver.cc +++ b/src/mem/ruby/tester/RaceyDriver.cc @@ -1,6 +1,6 @@ /* - * Copyright (c) 1999-2008 Mark D. Hill and David A. Wood + * Copyright (c) 1999-2005 Mark D. Hill and David A. Wood * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -32,36 +32,31 @@ * */ -#include "mem/ruby/common/Global.hh" -#include "mem/ruby/system/System.hh" +#include "mem/ruby/tester/Global_Tester.hh" #include "mem/ruby/tester/RaceyDriver.hh" -#include "mem/ruby/eventqueue/RubyEventQueue.hh" -#include "RaceyPseudoThread.hh" -#include "mem/ruby/common/SubBlock.hh" +#include "mem/ruby/tester/EventQueue_Tester.hh" +#include "mem/ruby/tester/RaceyPseudoThread.hh" -RaceyDriver::RaceyDriver() +RaceyDriver::RaceyDriver(int num_procs, int tester_length) { - // 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; + m_num_procs = num_procs; + m_tester_length = tester_length; + eventQueue = new RubyEventQueue; // racey at least need two processors - assert(RubyConfig::numberOfProcessors() >= 2); + assert(m_num_procs >= 2); // init all racey pseudo threads - m_racey_pseudo_threads.setSize(RubyConfig::numberOfProcessors()); + m_racey_pseudo_threads.setSize(m_num_procs); 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); + eventQueue->scheduleEvent(this, g_DEADLOCK_THRESHOLD); } RaceyDriver::~RaceyDriver() @@ -71,20 +66,38 @@ RaceyDriver::~RaceyDriver() } } -void RaceyDriver::hitCallback(NodeID proc, SubBlock& data, CacheRequestType type, int thread) +void RaceyDriver::go() { + // tick both queues until everyone is done + while (m_done_counter != m_num_procs) { + libruby_tick(1); + eventQueue->triggerEvents(eventQueue->getTime() + 1); + } +} + + +void RaceyDriver::hitCallback(int64_t request_id) { - DEBUG_EXPR(TESTER_COMP, MedPrio, data); - m_racey_pseudo_threads[proc]->performCallback(proc, data); + ASSERT(requests.find(request_id) != requests.end()); + int proc = requests[request_id].first; + Address address = requests[request_id].second.address; + uint8_t * data = new uint8_t[4]; + for (int i = 0; i < 4; i++) { + data[i] = requests[request_id].second.data[i]; + } + requests[request_id].second.data; + m_racey_pseudo_threads[proc]->performCallback(proc, address, data); + requests.erase(request_id); } integer_t RaceyDriver::getInstructionCount(int procID) const { - return m_racey_pseudo_threads[procID]->getInstructionCounter(); + // return m_racey_pseudo_threads[procID]->getInstructionCounter(); + assert(0); } int RaceyDriver::runningThreads() { - return RubyConfig::numberOfProcessors() - m_done_counter; + return m_num_procs - m_done_counter; } // used to wake up thread 0 whenever other thread finishes @@ -96,12 +109,12 @@ void RaceyDriver::registerThread0Wakeup() void RaceyDriver::joinThread() { m_done_counter++; - if (m_done_counter == RubyConfig::numberOfProcessors()) { - m_finish_time = g_eventQueue_ptr->getTime(); + if (m_done_counter == m_num_procs) { + m_finish_time = eventQueue->getTime(); } if(m_wakeup_thread0) { - g_eventQueue_ptr->scheduleEvent(m_racey_pseudo_threads[0], 1); + eventQueue->scheduleEvent(m_racey_pseudo_threads[0], 1); m_wakeup_thread0 = false; } } @@ -114,14 +127,14 @@ void RaceyDriver::wakeup() } // schedule next wakeup - if (m_done_counter < RubyConfig::numberOfProcessors()) { - g_eventQueue_ptr->scheduleEvent(this, g_DEADLOCK_THRESHOLD); + if (m_done_counter < m_num_procs) { + eventQueue->scheduleEvent(this, g_DEADLOCK_THRESHOLD); } } void RaceyDriver::printStats(ostream& out) const { - assert(m_done_counter == RubyConfig::numberOfProcessors()); + assert(m_done_counter == m_num_procs); out << endl; out << "RaceyDriver Stats" << endl; out << "---------------------" << endl; diff --git a/src/mem/ruby/tester/RaceyDriver.hh b/src/mem/ruby/tester/RaceyDriver.hh index a3e35b47c..cc2130ef9 100644 --- a/src/mem/ruby/tester/RaceyDriver.hh +++ b/src/mem/ruby/tester/RaceyDriver.hh @@ -1,6 +1,6 @@ /* - * Copyright (c) 1999-2008 Mark D. Hill and David A. Wood + * Copyright (c) 1999-2005 Mark D. Hill and David A. Wood * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -38,15 +38,25 @@ #ifndef RACEYDRIVER_H #define RACEYDRIVER_H -#include "mem/ruby/common/Global.hh" -#include "mem/ruby/common/Driver.hh" +#include "mem/ruby/tester/Global_Tester.hh" +#include "mem/ruby/tester/Driver_Tester.hh" +#include "mem/ruby/tester/RaceyPseudoThread.hh" +#include <map> +#include "mem/ruby/libruby.hh" -class RaceyPseudoThread; +#define g_DEADLOCK_THRESHOLD 5000 -class RaceyDriver : public Driver, public Consumer { + +struct address_data { + Address address; + uint8_t * data; +}; + +class RaceyDriver : public Driver_Tester, public Consumer { public: + friend class RaceyPseudoThread; // Constructors - RaceyDriver(); + RaceyDriver(int num_procs, int tester_length); // Destructor ~RaceyDriver(); @@ -59,11 +69,12 @@ public: return m_racey_pseudo_threads[0]->getInitializedState(); }; - void hitCallback(NodeID proc, SubBlock& data, CacheRequestType type, int thread); + void hitCallback(int64_t request_id); void wakeup(); void printStats(ostream& out) const; void clearStats() {} void printConfig(ostream& out) const {} + void go(); integer_t getInstructionCount(int procID) const; @@ -81,6 +92,7 @@ public: } void print(ostream& out) const; + private: // Private copy constructor and assignment operator @@ -91,8 +103,11 @@ private: Vector<RaceyPseudoThread*> m_racey_pseudo_threads; int m_done_counter; bool m_wakeup_thread0; - Time m_finish_time; + map <int64_t, pair <int, struct address_data> > requests; + RubyEventQueue * eventQueue; + int m_num_procs; + int m_tester_length; }; // Output operator declaration @@ -110,3 +125,4 @@ ostream& operator<<(ostream& out, const RaceyDriver& obj) } #endif //RACEYDRIVER_H + diff --git a/src/mem/ruby/tester/RaceyPseudoThread.cc b/src/mem/ruby/tester/RaceyPseudoThread.cc new file mode 100644 index 000000000..e5e1c1169 --- /dev/null +++ b/src/mem/ruby/tester/RaceyPseudoThread.cc @@ -0,0 +1,353 @@ +/* + * Copyright (c) 1999 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. + */ + +/* + * Description: see RaceyPseudoThread.hh + */ + +#include "mem/ruby/tester/RaceyPseudoThread.hh" +#include "mem/ruby/config/RubyConfig.hh" +#include "mem/ruby/tester/RaceyDriver.hh" +#include "gzstream.hh" + +RaceyPseudoThread::RaceyPseudoThread(NodeID id, RaceyDriver& driver) + : m_driver(driver), m_proc_id(id) { + + resetIC(); // IC contains the committed instruction number + m_last_progress = 0; + m_done = false; + m_stop = 0; + m_driver.eventQueue->scheduleEvent(this, 1); +} + +RaceyPseudoThread::~RaceyPseudoThread() { +} + +void RaceyPseudoThread::checkForDeadlock() { + Time current_time = m_driver.eventQueue->getTime(); + if(!m_done && (current_time - m_last_progress) > g_DEADLOCK_THRESHOLD) { + WARN_EXPR(m_proc_id); + WARN_EXPR(m_ic_counter); + WARN_EXPR(m_last_progress); + ERROR_MSG("Deadlock detected."); + } +} + +void RaceyPseudoThread::performCallback(int proc, Address address, uint8_t * data ) { + assert(proc == m_proc_id); + + DEBUG_EXPR(TESTER_COMP, LowPrio, proc); + DEBUG_EXPR(TESTER_COMP, LowPrio, address); + + + m_last_progress = m_driver.eventQueue->getTime(); + + if(m_read) { + int b0, b1, b2, b3; + b0 = data[0]; b0 <<= 0; + b1 = data[1]; b1 <<= 8; + b2 = data[2]; b2 <<= 16; + b3 = data[3]; b3 <<= 24; + m_value = b0 | b1 | b2 | b3; + } else { + char b0, b1, b2, b3; + b0 = (m_value>>0)&0xFF; data[0] = b0; + b1 = (m_value>>8)&0xFF; data[1] = b1; + b2 = (m_value>>16)&0xFF; data[2] = b2; + b3 = (m_value>>24)&0xFF; data[3] = b3; + } + + // schedule wakeup for next requests in next cycle + m_driver.eventQueue->scheduleEvent(this, 1); + + // new instruction + m_ic_counter++; + +} + +void RaceyPseudoThread::wakeup() { + // for debug + if(m_stop != 0) { + cout << m_proc_id << " " << m_stop << ((m_read)? " read ":" written ") << m_value; + if(0) cout << " [" << m_driver.eventQueue->getTime() << "]"; + cout << endl; + } + + assert(!m_done); + + // Note, this function can not have ANY local variable! + + switch(m_stop) { + case 0: + break; + case 1: + goto L1; + case 2: + goto L2; + case 3: + goto L3; + case 4: + goto L4; + case 5: + goto L5; + case 6: + goto L6; + case 7: + goto L7; + case 8: + goto L8; + case 9: + goto L9; + case 10: + goto L10; + default: + WARN_EXPR(m_stop); + ERROR_MSG("RaceyPseudoThread: Bad context point!"); + } + + // + // initialization + // + if(m_proc_id == 0) { + for(m_looper = 0; m_looper < m_driver.m_num_procs; m_looper++) { + store_sig(m_looper, m_looper+1); + m_stop = 6; return; +L6: {}; + } + for(m_looper = 0; m_looper < M_ELEM; m_looper++) { + store_m(m_looper, M_ELEM-m_looper); + m_stop = 7; return; +L7: {}; + } + + // init done + m_initialized = true; + } else { + // other processors + if(!m_driver.Thread0Initialized()) { + // wait for processors 0 + m_driver.eventQueue->scheduleEvent(this, 1); + return; + } + } + + cout << "Thread " << m_proc_id << " started in parallel phase" << endl; + + // + // main thread body + // + for(m_looper = 0 ; m_looper < m_driver.m_tester_length; m_looper++) { + /* m_value = */ load_sig(m_proc_id); + m_stop = 1; return; +L1: {}; + m_num = m_value; + m_index1 = m_num%M_ELEM; + /* m_value = */ load_m(m_index1); + m_stop = 2; return; +L2: {}; + m_num = mix(m_num, m_value); + m_index2 = m_num%M_ELEM; + /* m_value = */ load_m(m_index2); + m_stop = 3; return; +L3: {}; + m_num = mix(m_num, m_value); + store_m(m_index2, m_num); + m_stop = 4; return; +L4: {}; + store_sig(m_proc_id, m_num); + m_stop = 5; return; +L5: {}; + } // end for + + // + // compute final sig + // + if(m_proc_id == 0) { + // wait for other threads + while (m_driver.runningThreads() > 1) { + m_driver.registerThread0Wakeup(); + m_stop = 10; return; +L10: {}; + } + + /* m_value = */ load_sig(0); + m_stop = 8; return; +L8: {}; + m_final_sig = m_value; + for(m_looper = 1; m_looper < m_driver.m_num_procs; m_looper++) { + /* m_value = */ load_sig(m_looper); + m_stop = 9; return; +L9: {}; + m_final_sig = mix(m_value, m_final_sig); + } + } // processors 0 + + // done + m_driver.joinThread(); + m_done = true; +} + +void RaceyPseudoThread::load_sig(unsigned index) { + cout << m_proc_id << " : load_sig " << index << endl; + + m_read = true; + // timestamp, threadid, action, and logical address are used only by transactional memory, should be augmented + uint8_t * read_data = new uint8_t[4]; + + char name [] = "Sequencer_"; + char port_name [13]; + sprintf(port_name, "%s%d", name, m_proc_id); + + // pc is zero, problem? + int64_t request_id = libruby_issue_request(libruby_get_port_by_name(port_name), RubyRequest(sig(index), read_data, 4, 0, RubyRequestType_LD, RubyAccessMode_User)); + + ASSERT(m_driver.requests.find(request_id) == m_driver.requests.end()); + + struct address_data request_data; + request_data.address = Address(sig(index)); + request_data.data = read_data; + m_driver.requests.insert(make_pair(request_id, make_pair(m_proc_id, request_data))); + + /*sequencer()->makeRequest(CacheMsg(Address(sig(index)), Address(sig(index)), CacheRequestType_LD, + Address(physical_address_t(1)), + AccessModeType_UserMode, 4, + PrefetchBit_No, 0, Address(0), + 0, 0 , false)); */ +} + +void RaceyPseudoThread::load_m(unsigned index) { + // cout << m_proc_id << " : load_m " << index << endl; + + m_read = true; + uint8_t * read_data = new uint8_t[4]; + + char name [] = "Sequencer_"; + char port_name [13]; + sprintf(port_name, "%s%d", name, m_proc_id); + + // pc is zero, problem? + int64_t request_id = libruby_issue_request(libruby_get_port_by_name(port_name), RubyRequest(m(index), read_data, 4, 0, RubyRequestType_LD, RubyAccessMode_User)); + + ASSERT(m_driver.requests.find(request_id) == m_driver.requests.end()); + + struct address_data request_data; + request_data.address = Address(m(index)); + request_data.data = read_data; + m_driver.requests.insert(make_pair(request_id, make_pair(m_proc_id, request_data))); + + /*sequencer()->makeRequest(CacheMsg(Address(m(index)), Address(m(index)), CacheRequestType_LD, + Address(physical_address_t(1)), + AccessModeType_UserMode, 4, + PrefetchBit_No, 0, Address(0), + 0, 0, false)); */ +} + +void RaceyPseudoThread::store_sig(unsigned index, unsigned value) { + cout << m_proc_id << " : store_sig " << index << " " << value << endl; + + m_read = false; + m_value = value; + uint8_t * write_data = new uint8_t[4]; + + memcpy(write_data, &value, 4); + + char name [] = "Sequencer_"; + char port_name [13]; + sprintf(port_name, "%s%d", name, m_proc_id); + + // pc is zero, problem? + int64_t request_id = libruby_issue_request(libruby_get_port_by_name(port_name), RubyRequest(sig(index), write_data, 4, 0, RubyRequestType_ST, RubyAccessMode_User)); + + ASSERT(m_driver.requests.find(request_id) == m_driver.requests.end()); + + struct address_data request_data; + request_data.address = Address(sig(index)); + request_data.data = write_data; + m_driver.requests.insert(make_pair(request_id, make_pair(m_proc_id, request_data))); + + /*sequencer()->makeRequest(CacheMsg(Address(sig(index)), Address(sig(index)), CacheRequestType_ST, + Address(physical_address_t(1)), + AccessModeType_UserMode, 4, + PrefetchBit_No, 0, Address(0), + 0, 0, false)); */ +} + +void RaceyPseudoThread::store_m(unsigned index, unsigned value) { + //cout << m_proc_id << " : store_m " << index << endl; + + m_read = false; + m_value = value; + uint8_t * write_data = new uint8_t[4]; + memcpy(write_data, &value, 4); + + char name [] = "Sequencer_"; + char port_name [13]; + sprintf(port_name, "%s%d", name, m_proc_id); + + // pc is zero, problem? + int64_t request_id = libruby_issue_request(libruby_get_port_by_name(port_name), RubyRequest(m(index), write_data, 4, 0, RubyRequestType_ST, RubyAccessMode_User)); + + ASSERT(m_driver.requests.find(request_id) == m_driver.requests.end()); + + struct address_data request_data; + request_data.address = Address(m(index)); + request_data.data = write_data; + m_driver.requests.insert(make_pair(request_id, make_pair(m_proc_id, request_data))); + + /*sequencer()->makeRequest(CacheMsg(Address(m(index)), Address(m(index)), CacheRequestType_ST, + Address(physical_address_t(1)), + AccessModeType_UserMode, 4, + PrefetchBit_No, 0, Address(0), + 0, 0, false)); */ +} + +// Save and Load context of a thread +void RaceyPseudoThread::saveCPUStates(string filename) { + ogzstream out(filename.c_str()); + out.write((char*)&m_looper, sizeof(int)); + out.write((char*)&m_num, sizeof(unsigned)); + out.write((char*)&m_index1, sizeof(unsigned)); + out.write((char*)&m_index2, sizeof(unsigned)); + out.write((char*)&m_stop, sizeof(unsigned)); + out.close(); +} + +void RaceyPseudoThread::loadCPUStates(string filename) { + igzstream out(filename.c_str()); + out.read((char*)&m_looper, sizeof(int)); + out.read((char*)&m_num, sizeof(unsigned)); + out.read((char*)&m_index1, sizeof(unsigned)); + out.read((char*)&m_index2, sizeof(unsigned)); + out.read((char*)&m_stop, sizeof(unsigned)); + out.close(); +} + +void RaceyPseudoThread::print(ostream& out) const { + out << "[Racey Pseudo Thread: " << m_proc_id << "]" << endl; +} + diff --git a/src/mem/ruby/tester/RaceyPseudoThread.hh b/src/mem/ruby/tester/RaceyPseudoThread.hh new file mode 100644 index 000000000..9db4ad04a --- /dev/null +++ b/src/mem/ruby/tester/RaceyPseudoThread.hh @@ -0,0 +1,151 @@ +/* + * Copyright (c) 1999 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. + */ + +/* + * Description: This implements a pseudo racey thread which drives ruby timing + * simulator with access to two shared arrays. + * + */ + +#ifndef RACEYPSEUDOTHREAD_H +#define RACEYPSEUDOTHREAD_H + +#include "mem/ruby/tester/Global_Tester.hh" +#include "mem/ruby/common/Consumer.hh" +#include "mem/ruby/system/NodeID.hh" +#include "Address_Tester.hh" +#include "mem/ruby/libruby.hh" + +class RaceyDriver; + +class RaceyPseudoThread : public Consumer { +private: + // constants + static const int PRIME1 = 103072243; + static const int PRIME2 = 103995407; + static const int M_ELEM = 64; + + // m and sig array's starting address, + // each signature should occupy a cacheline + static const int SIG_ARR = 0; + static const int M_ARR = 0x10000; + static const int LINESIZE = 64; + + // get address of a element from the m and sig arrays + physical_address_t sig(unsigned index) { + assert(index < M_ARR/64); + return SIG_ARR + (index*64); + }; + physical_address_t m(unsigned index) { return M_ARR + (index*64); }; + +public: + // Constructors + RaceyPseudoThread(NodeID node, RaceyDriver& driver); + + // Destructor + ~RaceyPseudoThread(); + + // Public Methods + void performCallback(int proc, Address address, uint8_t * data); + + void wakeup(); + + integer_t getInstructionCount() { return m_ic_counter; }; + + unsigned getSignature() { assert(m_proc_id == 0); return m_final_sig; }; + + void checkForDeadlock(); + + // save and restore the thread state + void saveCPUStates(string filename); + void loadCPUStates(string filename); + + // reset IC to zero for next checkpoint + void resetIC() { m_ic_counter = 0; }; + + bool getInitializedState() { return m_initialized; }; + + void print(ostream& out) const; +private: + // Private Methods + + // mix two numbers + unsigned mix (unsigned i, unsigned j) { return (i + j * PRIME2) % PRIME1; }; + + // load or store the array + void load_sig(unsigned index); + void load_m(unsigned index); + void store_sig(unsigned index, unsigned value); + void store_m(unsigned index, unsigned value); + + // Private copy constructor and assignment operator + RaceyPseudoThread(const RaceyPseudoThread& obj); + RaceyPseudoThread& operator=(const RaceyPseudoThread& obj); + + // Data Members (m_ prefix) + RaceyDriver& m_driver; + NodeID m_proc_id; + + // are we done? + bool m_done; + + // [committed] instruction counter + int m_ic_counter; + + // last time we made progress + Time m_last_progress; + + // value of the callback block + bool m_read; + unsigned m_value; + + // final signature + unsigned m_final_sig; + + // local variables for the pseudo thread + int m_looper; + unsigned m_num, m_index1, m_index2, m_stop; + bool m_initialized; +}; + +// Output operator declaration +ostream& operator<<(ostream& out, const RaceyPseudoThread& obj); + +// ******************* Definitions ******************* + +// Output operator definition +extern inline +ostream& operator<<(ostream& out, const RaceyPseudoThread& obj) +{ + obj.print(out); + out << flush; + return out; +} + +#endif //RACEYPSEUDOTHREAD_H + diff --git a/src/mem/ruby/tester/RequestGenerator.cc b/src/mem/ruby/tester/RequestGenerator.cc deleted file mode 100644 index 4ee24544f..000000000 --- a/src/mem/ruby/tester/RequestGenerator.cc +++ /dev/null @@ -1,220 +0,0 @@ - -/* - * Copyright (c) 1999-2008 Mark D. Hill and David A. Wood - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/* - * $Id$ - * - */ - -#include "mem/ruby/tester/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/SpecifiedGenerator.cc b/src/mem/ruby/tester/SpecifiedGenerator.cc index 1c273eac3..63e4a7ae8 100644 --- a/src/mem/ruby/tester/SpecifiedGenerator.cc +++ b/src/mem/ruby/tester/SpecifiedGenerator.cc @@ -33,10 +33,6 @@ */ #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() { diff --git a/src/mem/ruby/tester/SpecifiedGenerator.hh b/src/mem/ruby/tester/SpecifiedGenerator.hh index 9aaaffba0..976947ce6 100644 --- a/src/mem/ruby/tester/SpecifiedGenerator.hh +++ b/src/mem/ruby/tester/SpecifiedGenerator.hh @@ -37,12 +37,10 @@ #ifndef SPECIFIEDGENERATOR_H #define SPECIFIEDGENERATOR_H -#include "mem/ruby/common/Global.hh" +#include "mem/ruby/tester/Global_Tester.hh" #include "mem/ruby/common/Consumer.hh" #include "mem/ruby/system/NodeID.hh" - -class Sequencer; -class SubBlock; +#include "Address_Tester.hh" class SpecifiedGenerator : public Consumer { public: @@ -54,7 +52,7 @@ public: // Public Methods virtual void wakeup() = 0; - virtual void performCallback(NodeID proc, SubBlock& data) = 0; + virtual void performCallback(NodeID proc, Address address) = 0; virtual void print(ostream& out) const = 0; protected: diff --git a/src/mem/ruby/tester/SyntheticDriver.cc b/src/mem/ruby/tester/SyntheticDriver.cc deleted file mode 100644 index f19baa202..000000000 --- a/src/mem/ruby/tester/SyntheticDriver.cc +++ /dev/null @@ -1,286 +0,0 @@ - -/* - * Copyright (c) 1999-2008 Mark D. Hill and David A. Wood - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/* - * $Id$ - * - */ - -#include "mem/ruby/common/Global.hh" -#include "mem/ruby/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 deleted file mode 100644 index 18c463e88..000000000 --- a/src/mem/ruby/tester/SyntheticDriver.hh +++ /dev/null @@ -1,118 +0,0 @@ - -/* - * Copyright (c) 1999-2008 Mark D. Hill and David A. Wood - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/* - * $Id$ - * - * Description: - * - */ - -#ifndef 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 deleted file mode 100644 index eafc04a92..000000000 --- a/src/mem/ruby/tester/Tester.cc +++ /dev/null @@ -1,112 +0,0 @@ - -/* - * Copyright (c) 1999-2008 Mark D. Hill and David A. Wood - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/* - * $Id$ - * - */ - -#include "mem/ruby/common/Global.hh" -#include "mem/ruby/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/main.cc b/src/mem/ruby/tester/main.cc index ba835b488..849206de9 100644 --- a/src/mem/ruby/tester/main.cc +++ b/src/mem/ruby/tester/main.cc @@ -32,10 +32,8 @@ * */ -#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" +#include "mem/slicc/main.hh" +#include "mem/ruby/tester/test_framework.hh" // ******************* // *** tester main *** @@ -43,6 +41,5 @@ int main(int argc, char *argv[]) { - //dsm: PRUNED - //tester_main(argc, argv); + tester_main(argc, argv); } diff --git a/src/mem/ruby/tester/main.hh b/src/mem/ruby/tester/main.hh index 3708d770d..ca036ddd7 100644 --- a/src/mem/ruby/tester/main.hh +++ b/src/mem/ruby/tester/main.hh @@ -27,9 +27,16 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +/* + * $Id$ + * + * Description: + * + */ + #ifndef MAIN_H #define MAIN_H -#include "mem/ruby/common/Global.hh" +#include "Global_Tester.hh" #endif //MAIN_H diff --git a/src/mem/ruby/tester/test_framework.cc b/src/mem/ruby/tester/test_framework.cc index 9886adc8d..6b7c7ddec 100644 --- a/src/mem/ruby/tester/test_framework.cc +++ b/src/mem/ruby/tester/test_framework.cc @@ -32,181 +32,233 @@ * */ -#include "mem/protocol/protocol_name.hh" +using namespace std; + #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 "mem/protocol/protocol_name.hh" #include "getopt.hh" -#include "mem/ruby/network/Network.hh" -#include "mem/ruby/recorder/CacheRecorder.hh" -#include "mem/ruby/recorder/Tracer.hh" +#include "mem/ruby/tester/DeterministicDriver.hh" +#include "mem/ruby/tester/RaceyDriver.hh" +#include "mem/ruby/tester/Driver_Tester.hh" -using namespace std; #include <string> #include <map> +#include <iostream> +#include <assert.h> +#include <vector> +#include <string> +#include <sstream> +#include <sys/wait.h> -// Maurice -// extern "C" { -// #include "simics/api.hh" -// }; +#include "mem/ruby/libruby.hh" -#include "mem/gems_common/ioutil/confio.hh" -#include "mem/gems_common/ioutil/initvar.hh" +// FIXME: should really make this a class if can't figure out how to make a function to get the ruby parameter -// 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 set_defaults(); 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 void hit_callback(int64_t request_id); + +// Tester variables +string driver_type; +string generator_type; +Driver_Tester * m_driver_ptr; +int g_tester_length; +int num_completions; +Time g_think_time; +Time g_wait_time; +int num_procs; + +// Debugger variables +Debug * debug_ptr; +string g_debug_verbosity_string; +string g_debug_filter_string; +string g_debug_output_filename; +Time g_debug_start_time; -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 ) +vector<string> tokenizeMyString(string str, string delims) { - init_simulator(); + vector<string> tokens; + char* pch; + char* tmp; + const char* c_delims = delims.c_str(); + tmp = new char[str.length()+1]; + strcpy(tmp, str.c_str()); + pch = strtok(tmp, c_delims); + while (pch != NULL) { + tokens.push_back(string(pch)); + pch = strtok(NULL, c_delims); + } + delete [] tmp; + return tokens; } -static void tester_generate_values( void ) + +vector<string> getPorts(const char* cfg_script, int cfg_script_argc, char* cfg_script_argv[]) { + stringstream cfg_output; + + // first we execute the Ruby-lang configuration script + int fd[2]; + int pid; + if (pipe(fd) == -1) { + perror("Error Creating Pipe"); + exit(EXIT_FAILURE); + } + + pid = fork(); + if (pid == -1){ + perror("Error forking"); + exit(EXIT_FAILURE); + } + + if (!pid) { + // child + close(fd[0]); // close the read end of the pipe + // replace stdout with the write pipe + if (dup2(fd[1], STDOUT_FILENO) == -1) { + perror("Error redirecting stdout"); + exit(EXIT_FAILURE); + } +#define QUOTE_MACRO(x, y) QUOTE_TXT(x,y) +#define QUOTE_TXT(x, y) #x y + if (execlp("ruby", "ruby", "-I", QUOTE_MACRO(GEMS_ROOT, "/ruby/config"), QUOTE_MACRO(GEMS_ROOT, "/tests/list_ports.rb"), cfg_script, NULL)) { + perror("execlp"); + exit(EXIT_FAILURE); + } + } else { + close(fd[1]); + + int child_status; + if (wait(&child_status) == -1) { + perror("wait"); + exit(EXIT_FAILURE); + } + if (child_status != EXIT_SUCCESS) { + exit(EXIT_FAILURE); + } + + char buf[100]; + int bytes_read; + while( (bytes_read = read(fd[0], buf, 100)) > 0 ) { + for (int i=0;i<bytes_read;i++) { + cfg_output << buf[i]; + } + } + assert(bytes_read == 0); + close(fd[0]); + } + string line; + getline(cfg_output, line); + + return tokenizeMyString(line, " "); } + + 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(); + const char* cfg_file = argv[1]; + + set_defaults(); parseOptions(argc, argv); - ruby_initvar->allocate(); + libruby_init(cfg_file); + libruby_print_config(std::cout); - g_system_ptr->printConfig(cout); - cout << "Testing clear stats..."; - g_system_ptr->clearStats(); - cout << "Done." << endl; - //free( default_param ); - //delete ruby_initvar; -} + vector<string> port_names = getPorts(cfg_file, 0, NULL); + vector<RubyPortHandle> ports; -void tester_destroy() -{ - g_system_ptr->printStats(cout); - g_debug_ptr->closeDebugOutputFile(); + for (vector<string>::const_iterator it = port_names.begin(); it != port_names.end(); it++) + ports.push_back(libruby_get_port((*it).c_str(), hit_callback)); - free(my_default_param); - delete my_initvar; - // Clean up - destroy_simulator(); - cerr << "Success: " << CURRENT_PROTOCOL << endl; -} + debug_ptr = new Debug( g_debug_filter_string.c_str(), + g_debug_verbosity_string.c_str(), + g_debug_start_time, + g_debug_output_filename.c_str() ); -void tester_install_opal(mf_opal_api_t* opal_api, mf_ruby_api_t* ruby_api) -{ - std::cout << __FILE__ << "(" << __LINE__ << "): Not implemented" << std::endl; + if (driver_type == "Deterministic") { + m_driver_ptr = new DeterministicDriver(generator_type, num_completions, num_procs, g_think_time, g_wait_time, g_tester_length); + } + else if (driver_type == "Racey") { + m_driver_ptr = new RaceyDriver(num_procs, g_tester_length); + } + /* else if (driver_type == "Synthetic") { + m_driver_ptr = new SyntheticDriver(); + } + }*/ + + m_driver_ptr->go(); } -void tester_record_cache() +void tester_destroy() { - 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; + m_driver_ptr->printStats(cout); + libruby_destroy(); + cerr << "Success: " << CURRENT_PROTOCOL << endl; } -void tester_playback_trace() + +void hit_callback(int64_t request_id) { - 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."); - } + m_driver_ptr->hitCallback(request_id); } // ************************************************************************ // *** 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'}, + {"number of processors", required_argument, NULL, 'p'}, + {"test run length", required_argument, NULL, 'l'}, + {"debugger verbosity", required_argument, NULL, 'v'}, + {"debugger filter component", required_argument, NULL, 'c'}, + {"debugger output file", required_argument, NULL, 'o'}, + {"debugger start time", required_argument, NULL, 's'}, + {"generator think time", required_argument, NULL, 'k'}, + {"generator wait time", required_argument, NULL, 'w'}, + {"driver type", required_argument, NULL, 'd'}, + {"generator type", required_argument, NULL, 'g'}, + {"num completions before pass", required_argument, NULL, 'n'}, {NULL, 0, NULL, 0} }; + +// This is awkward and temporary, need the defaults config, and also need functions to +// just lookup a parameter in the configuration file +// Ideally the default values are set by libruby_init and then a function is provided to +// set values at run-time +static void set_defaults() { + g_tester_length = 0; + g_think_time = 5; + g_wait_time = 20; + + num_procs = 1; + num_completions = 1; + driver_type = "Deterministic"; + generator_type = "DetermInvGenerator"; + g_debug_verbosity_string = "none"; + g_debug_filter_string = "none"; + g_debug_output_filename = "none"; + g_debug_start_time = 0; +} + static void parseOptions(int argc, char **argv) { cout << "Parsing command line arguments:" << endl; @@ -229,21 +281,14 @@ static void parseOptions(int argc, char **argv) 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 'p': + checkArg(c); + cout << " number of processors = " << optarg << endl; + num_procs = atoi( optarg ); + break; case 'v': checkArg(c); cout << " verbosity string = " << optarg << endl; @@ -251,22 +296,8 @@ static void parseOptions(int argc, char **argv) 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(); - } - } + g_debug_verbosity_string = strdup( optarg ); break; - } - case 'l': { checkArg(c); g_tester_length = atoi(optarg); @@ -276,44 +307,15 @@ static void parseOptions(int argc, char **argv) } break; } - - case 'q': { + case 'c': checkArg(c); - g_synthetic_locks = atoi(optarg); - cout << " locks in synthetic workload = " << g_synthetic_locks << endl; - if (g_synthetic_locks == 0) { + cout << " component filter string = " << optarg << endl; + error = Debug::checkFilterString( optarg ); + if (error) { usageInstructions(); } + g_debug_filter_string = strdup( optarg ); 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); @@ -321,71 +323,44 @@ static void parseOptions(int argc, char **argv) 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(); - } + g_debug_start_time = start_time; break; } - - case 't': { + case 'k': { 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(); - } - + g_think_time = atoi(optarg); break; } - - case 'k': { + case 'w': { checkArg(c); - g_think_time = atoi(optarg); + g_wait_time = atoi(optarg); break; } - case 'o': checkArg(c); cout << " output file = " << optarg << endl; - DEBUG_OUTPUT_FILENAME = strdup( optarg ); + g_debug_output_filename = strdup( optarg ); break; - - case 'z': + case 'd': checkArg(c); - trace_filename = string(optarg); - cout << " tracefile = " << trace_filename << endl; + cout << " driver type = " << optarg << endl; + driver_type = strdup( optarg ); + break; + case 'g': + checkArg(c); + cout << " generator type = " << optarg << endl; + generator_type = strdup( optarg ); + break; + case 'n': + checkArg(c); + cout << " num completions before pass = " << optarg << endl; + num_completions = atoi( optarg ); 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() @@ -408,10 +383,8 @@ static void usageInstructions() 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(); + debug_ptr->usageInstructions(); cerr << endl; exit(1); diff --git a/src/mem/ruby/tester/test_framework.hh b/src/mem/ruby/tester/test_framework.hh index 5e9e9363b..ade27a78f 100644 --- a/src/mem/ruby/tester/test_framework.hh +++ b/src/mem/ruby/tester/test_framework.hh @@ -37,10 +37,8 @@ #ifndef TESTFRAMEWORK_H #define TESTFRAMEWORK_H -#include "mem/ruby/common/Global.hh" -#include "mem/ruby/interfaces/mf_api.hh" +#include "mem/ruby/tester/Global_Tester.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 |