From e983ef9e8c6749c1cd0bf083a2092cb4683d0346 Mon Sep 17 00:00:00 2001 From: Brad Beckmann Date: Tue, 24 Aug 2010 12:07:22 -0700 Subject: testers: move testers to a new directory This patch moves the testers to a new subdirectory under src/cpu and includes the necessary fixes to work with latest m5 initialization patches. --HG-- rename : configs/example/determ_test.py => configs/example/ruby_direct_test.py rename : src/cpu/directedtest/DirectedGenerator.cc => src/cpu/testers/directedtest/DirectedGenerator.cc rename : src/cpu/directedtest/DirectedGenerator.hh => src/cpu/testers/directedtest/DirectedGenerator.hh rename : src/cpu/directedtest/InvalidateGenerator.cc => src/cpu/testers/directedtest/InvalidateGenerator.cc rename : src/cpu/directedtest/InvalidateGenerator.hh => src/cpu/testers/directedtest/InvalidateGenerator.hh rename : src/cpu/directedtest/RubyDirectedTester.cc => src/cpu/testers/directedtest/RubyDirectedTester.cc rename : src/cpu/directedtest/RubyDirectedTester.hh => src/cpu/testers/directedtest/RubyDirectedTester.hh rename : src/cpu/directedtest/RubyDirectedTester.py => src/cpu/testers/directedtest/RubyDirectedTester.py rename : src/cpu/directedtest/SConscript => src/cpu/testers/directedtest/SConscript rename : src/cpu/directedtest/SeriesRequestGenerator.cc => src/cpu/testers/directedtest/SeriesRequestGenerator.cc rename : src/cpu/directedtest/SeriesRequestGenerator.hh => src/cpu/testers/directedtest/SeriesRequestGenerator.hh rename : src/cpu/memtest/MemTest.py => src/cpu/testers/memtest/MemTest.py rename : src/cpu/memtest/SConscript => src/cpu/testers/memtest/SConscript rename : src/cpu/memtest/memtest.cc => src/cpu/testers/memtest/memtest.cc rename : src/cpu/memtest/memtest.hh => src/cpu/testers/memtest/memtest.hh rename : src/cpu/rubytest/Check.cc => src/cpu/testers/rubytest/Check.cc rename : src/cpu/rubytest/Check.hh => src/cpu/testers/rubytest/Check.hh rename : src/cpu/rubytest/CheckTable.cc => src/cpu/testers/rubytest/CheckTable.cc rename : src/cpu/rubytest/CheckTable.hh => src/cpu/testers/rubytest/CheckTable.hh rename : src/cpu/rubytest/RubyTester.cc => src/cpu/testers/rubytest/RubyTester.cc rename : src/cpu/rubytest/RubyTester.hh => src/cpu/testers/rubytest/RubyTester.hh rename : src/cpu/rubytest/RubyTester.py => src/cpu/testers/rubytest/RubyTester.py rename : src/cpu/rubytest/SConscript => src/cpu/testers/rubytest/SConscript --- src/cpu/testers/rubytest/Check.cc | 356 +++++++++++++++++++++++++++++++++ src/cpu/testers/rubytest/Check.hh | 89 +++++++++ src/cpu/testers/rubytest/CheckTable.cc | 130 ++++++++++++ src/cpu/testers/rubytest/CheckTable.hh | 81 ++++++++ src/cpu/testers/rubytest/RubyTester.cc | 195 ++++++++++++++++++ src/cpu/testers/rubytest/RubyTester.hh | 148 ++++++++++++++ src/cpu/testers/rubytest/RubyTester.py | 38 ++++ src/cpu/testers/rubytest/SConscript | 47 +++++ 8 files changed, 1084 insertions(+) create mode 100644 src/cpu/testers/rubytest/Check.cc create mode 100644 src/cpu/testers/rubytest/Check.hh create mode 100644 src/cpu/testers/rubytest/CheckTable.cc create mode 100644 src/cpu/testers/rubytest/CheckTable.hh create mode 100644 src/cpu/testers/rubytest/RubyTester.cc create mode 100644 src/cpu/testers/rubytest/RubyTester.hh create mode 100644 src/cpu/testers/rubytest/RubyTester.py create mode 100644 src/cpu/testers/rubytest/SConscript (limited to 'src/cpu/testers/rubytest') diff --git a/src/cpu/testers/rubytest/Check.cc b/src/cpu/testers/rubytest/Check.cc new file mode 100644 index 000000000..9ace655a8 --- /dev/null +++ b/src/cpu/testers/rubytest/Check.cc @@ -0,0 +1,356 @@ +/* + * Copyright (c) 1999-2008 Mark D. Hill and David A. Wood + * Copyright (c) 2009 Advanced Micro Devices, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "cpu/testers/rubytest/Check.hh" +#include "mem/ruby/common/SubBlock.hh" +#include "mem/ruby/system/Sequencer.hh" +#include "mem/ruby/system/System.hh" + +typedef RubyTester::SenderState SenderState; + +Check::Check(const Address& address, const Address& pc, + int _num_cpu_sequencers, RubyTester* _tester) + : m_num_cpu_sequencers(_num_cpu_sequencers), m_tester_ptr(_tester) +{ + 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() +{ + DPRINTF(RubyTest, "initiating\n"); + debugPrint(); + + // currently no protocols support prefetches + if (false && (random() & 0xf) == 0) { + initiatePrefetch(); // Prefetch from random processor + } + + if (m_status == TesterStatus_Idle) { + initiateAction(); + } else if (m_status == TesterStatus_Ready) { + initiateCheck(); + } else { + // Pending - do nothing + DPRINTF(RubyTest, + "initiating action/check - failed: action/check is pending\n"); + } +} + +void +Check::initiatePrefetch() +{ + DPRINTF(RubyTest, "initiating prefetch\n"); + + int index = random() % m_num_cpu_sequencers; + RubyTester::CpuPort* port = + safe_cast(m_tester_ptr->getCpuPort(index)); + + Request::Flags flags; + flags.set(Request::PREFETCH); + + Packet::Command cmd; + + // 1 in 8 chance this will be an exclusive prefetch + if ((random() & 0x7) != 0) { + cmd = MemCmd::ReadReq; + + // 50% chance that the request will be an instruction fetch + if ((random() & 0x1) == 0) { + flags.set(Request::INST_FETCH); + } + } else { + cmd = MemCmd::WriteReq; + flags.set(Request::PF_EXCLUSIVE); + } + + // Prefetches are assumed to be 0 sized + Request *req = new Request(m_address.getAddress(), 0, flags, curTick, + m_pc.getAddress()); + + PacketPtr pkt = new Packet(req, cmd, port->idx); + + // push the subblock onto the sender state. The sequencer will + // update the subblock on the return + pkt->senderState = + new SenderState(m_address, req->getSize(), pkt->senderState); + + if (port->sendTiming(pkt)) { + DPRINTF(RubyTest, "successfully initiated prefetch.\n"); + } else { + // If the packet did not issue, must delete + SenderState* senderState = safe_cast(pkt->senderState); + pkt->senderState = senderState->saved; + delete senderState; + delete pkt->req; + delete pkt; + + DPRINTF(RubyTest, + "prefetch initiation failed because Port was busy.\n"); + } +} + +void +Check::initiateAction() +{ + DPRINTF(RubyTest, "initiating Action\n"); + assert(m_status == TesterStatus_Idle); + + int index = random() % m_num_cpu_sequencers; + RubyTester::CpuPort* port = + safe_cast(m_tester_ptr->getCpuPort(index)); + + Request::Flags flags; + + // Create the particular address for the next byte to be written + Address writeAddr(m_address.getAddress() + m_store_count); + + // Stores are assumed to be 1 byte-sized + Request *req = new Request(writeAddr.getAddress(), 1, flags, curTick, + m_pc.getAddress()); + + Packet::Command cmd; + + // 1 out of 8 chance, issue an atomic rather than a write + // if ((random() & 0x7) == 0) { + // cmd = MemCmd::SwapReq; + // } else { + cmd = MemCmd::WriteReq; + // } + + PacketPtr pkt = new Packet(req, cmd, port->idx); + uint8_t* writeData = new uint8_t; + *writeData = m_value + m_store_count; + pkt->dataDynamic(writeData); + + DPRINTF(RubyTest, "data 0x%x check 0x%x\n", + *(pkt->getPtr()), *writeData); + + // push the subblock onto the sender state. The sequencer will + // update the subblock on the return + pkt->senderState = + new SenderState(writeAddr, req->getSize(), pkt->senderState); + + if (port->sendTiming(pkt)) { + DPRINTF(RubyTest, "initiating action - successful\n"); + DPRINTF(RubyTest, "status before action update: %s\n", + (TesterStatus_to_string(m_status)).c_str()); + m_status = TesterStatus_Action_Pending; + } else { + // If the packet did not issue, must delete + // Note: No need to delete the data, the packet destructor + // will delete it + SenderState* senderState = safe_cast(pkt->senderState); + pkt->senderState = senderState->saved; + delete senderState; + delete pkt->req; + delete pkt; + + DPRINTF(RubyTest, "failed to initiate action - sequencer not ready\n"); + } + + DPRINTF(RubyTest, "status after action update: %s\n", + (TesterStatus_to_string(m_status)).c_str()); +} + +void +Check::initiateCheck() +{ + DPRINTF(RubyTest, "Initiating Check\n"); + assert(m_status == TesterStatus_Ready); + + int index = random() % m_num_cpu_sequencers; + RubyTester::CpuPort* port = + safe_cast(m_tester_ptr->getCpuPort(index)); + + Request::Flags flags; + + // 50% chance that the request will be an instruction fetch + if ((random() & 0x1) == 0) { + flags.set(Request::INST_FETCH); + } + + // Checks are sized depending on the number of bytes written + Request *req = new Request(m_address.getAddress(), CHECK_SIZE, flags, + curTick, m_pc.getAddress()); + + PacketPtr pkt = new Packet(req, MemCmd::ReadReq, port->idx); + uint8_t* dataArray = new uint8_t[CHECK_SIZE]; + pkt->dataDynamicArray(dataArray); + + // push the subblock onto the sender state. The sequencer will + // update the subblock on the return + pkt->senderState = + new SenderState(m_address, req->getSize(), pkt->senderState); + + if (port->sendTiming(pkt)) { + DPRINTF(RubyTest, "initiating check - successful\n"); + DPRINTF(RubyTest, "status before check update: %s\n", + TesterStatus_to_string(m_status).c_str()); + m_status = TesterStatus_Check_Pending; + } else { + // If the packet did not issue, must delete + // Note: No need to delete the data, the packet destructor + // will delete it + SenderState* senderState = safe_cast(pkt->senderState); + pkt->senderState = senderState->saved; + delete senderState; + delete pkt->req; + delete pkt; + + DPRINTF(RubyTest, "failed to initiate check - cpu port not ready\n"); + } + + DPRINTF(RubyTest, "status after check update: %s\n", + TesterStatus_to_string(m_status).c_str()); +} + +void +Check::performCallback(NodeID proc, SubBlock* data) +{ + Address address = data->getAddress(); + + // This isn't exactly right since we now have multi-byte checks + // assert(getAddress() == address); + + assert(getAddress().getLineAddress() == address.getLineAddress()); + assert(data != NULL); + + DPRINTF(RubyTest, "RubyTester Callback\n"); + debugPrint(); + + if (m_status == TesterStatus_Action_Pending) { + DPRINTF(RubyTest, "Action callback write value: %d, currently %d\n", + (m_value + m_store_count), data->getByte(0)); + // Perform store one byte at a time + data->setByte(0, (m_value + m_store_count)); + m_store_count++; + if (m_store_count == CHECK_SIZE) { + m_status = TesterStatus_Ready; + } else { + m_status = TesterStatus_Idle; + } + DPRINTF(RubyTest, "Action callback return data now %d\n", + data->getByte(0)); + } else if (m_status == TesterStatus_Check_Pending) { + DPRINTF(RubyTest, "Check callback\n"); + // Perform load/check + for (int byte_number=0; byte_numbergetByte(byte_number)) { + 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"); + } + } + DPRINTF(RubyTest, "Action/check success\n"); + debugPrint(); + + // successful check complete, increment complete + m_tester_ptr->incrementCheckCompletions(); + + 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"); + } + + DPRINTF(RubyTest, "proc: %d, Address: 0x%x\n", proc, + getAddress().getLineAddress()); + DPRINTF(RubyTest, "Callback done\n"); + debugPrint(); +} + +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; +} + +void +Check::pickValue() +{ + assert(m_status == TesterStatus_Idle); + m_status = TesterStatus_Idle; + m_value = random() & 0xff; // One byte + m_store_count = 0; +} + +void +Check::pickInitiatingNode() +{ + assert(m_status == TesterStatus_Idle || m_status == TesterStatus_Ready); + m_status = TesterStatus_Idle; + m_initiatingNode = (random() % m_num_cpu_sequencers); + DPRINTF(RubyTest, "picked initiating node %d\n", m_initiatingNode); + m_store_count = 0; +} + +void +Check::print(std::ostream& out) const +{ + out << "[" + << m_address << ", value: " + << (int)m_value << ", status: " + << m_status << ", initiating node: " + << m_initiatingNode << ", store_count: " + << m_store_count + << "]" << std::flush; +} + +void +Check::debugPrint() +{ + DPRINTF(RubyTest, + "[%#x, value: %d, status: %s, initiating node: %d, store_count: %d]\n", + m_address.getAddress(), (int)m_value, + TesterStatus_to_string(m_status).c_str(), + m_initiatingNode, m_store_count); +} diff --git a/src/cpu/testers/rubytest/Check.hh b/src/cpu/testers/rubytest/Check.hh new file mode 100644 index 000000000..1ce795a21 --- /dev/null +++ b/src/cpu/testers/rubytest/Check.hh @@ -0,0 +1,89 @@ +/* + * Copyright (c) 1999-2008 Mark D. Hill and David A. Wood + * Copyright (c) 2009 Advanced Micro Devices, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __CPU_RUBYTEST_CHECK_HH__ +#define __CPU_RUBYTEST_CHECK_HH__ + +#include + +#include "cpu/testers/rubytest/RubyTester.hh" +#include "mem/protocol/AccessModeType.hh" +#include "mem/protocol/TesterStatus.hh" +#include "mem/ruby/common/Address.hh" +#include "mem/ruby/common/Global.hh" +#include "mem/ruby/system/NodeID.hh" + +class SubBlock; + +const int CHECK_SIZE_BITS = 2; +const int CHECK_SIZE = (1 << CHECK_SIZE_BITS); + +class Check +{ + public: + Check(const Address& address, const Address& pc, int _num_cpu_sequencer, + RubyTester* _tester); + + 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(std::ostream& out) const; + + private: + void initiatePrefetch(); + void initiateAction(); + void initiateCheck(); + + void pickValue(); + void pickInitiatingNode(); + + void debugPrint(); + + TesterStatus m_status; + uint8 m_value; + int m_store_count; + NodeID m_initiatingNode; + Address m_address; + Address m_pc; + AccessModeType m_access_mode; + int m_num_cpu_sequencers; + RubyTester* m_tester_ptr; +}; + +inline std::ostream& +operator<<(std::ostream& out, const Check& obj) +{ + obj.print(out); + out << std::flush; + return out; +} + +#endif // __CPU_RUBYTEST_CHECK_HH__ diff --git a/src/cpu/testers/rubytest/CheckTable.cc b/src/cpu/testers/rubytest/CheckTable.cc new file mode 100644 index 000000000..728ad0303 --- /dev/null +++ b/src/cpu/testers/rubytest/CheckTable.cc @@ -0,0 +1,130 @@ +/* + * Copyright (c) 1999-2008 Mark D. Hill and David A. Wood + * Copyright (c) 2009 Advanced Micro Devices, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "base/intmath.hh" +#include "cpu/testers/rubytest/Check.hh" +#include "cpu/testers/rubytest/CheckTable.hh" +#include "cpu/testers/rubytest/CheckTable.hh" + +CheckTable::CheckTable(int _num_cpu_sequencers, RubyTester* _tester) + : m_num_cpu_sequencers(_num_cpu_sequencers), m_tester_ptr(_tester) +{ + 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]; +} + +void +CheckTable::addCheck(const Address& address) +{ + if (floorLog2(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.count(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()), + m_num_cpu_sequencers, m_tester_ptr); + for (int i = 0; i < CHECK_SIZE; i++) { + // Insert it once per byte + m_lookup_map[Address(address.getAddress() + i)] = check_ptr; + } + m_check_vector.push_back(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); + + m5::hash_map::iterator i = m_lookup_map.find(address); + + if (i == m_lookup_map.end()) + return NULL; + + Check* check = i->second; + assert(check != NULL); + return check; +} + +void +CheckTable::print(std::ostream& out) const +{ +} diff --git a/src/cpu/testers/rubytest/CheckTable.hh b/src/cpu/testers/rubytest/CheckTable.hh new file mode 100644 index 000000000..5a4ead337 --- /dev/null +++ b/src/cpu/testers/rubytest/CheckTable.hh @@ -0,0 +1,81 @@ +/* + * Copyright (c) 1999-2008 Mark D. Hill and David A. Wood + * Copyright (c) 2009 Advanced Micro Devices, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __CPU_RUBYTEST_CHECKTABLE_HH__ +#define __CPU_RUBYTEST_CHECKTABLE_HH__ + +#include +#include + +#include "base/hashmap.hh" +#include "mem/ruby/common/Address.hh" +#include "mem/ruby/common/Global.hh" + +class Check; +class RubyTester; + +class CheckTable +{ + public: + CheckTable(int _num_cpu_sequencers, RubyTester* _tester); + ~CheckTable(); + + 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(std::ostream& out) const; + + private: + void addCheck(const Address& address); + + // Private copy constructor and assignment operator + CheckTable(const CheckTable& obj); + CheckTable& operator=(const CheckTable& obj); + + std::vector m_check_vector; + m5::hash_map m_lookup_map; + + int m_num_cpu_sequencers; + RubyTester* m_tester_ptr; +}; + +inline std::ostream& +operator<<(std::ostream& out, const CheckTable& obj) +{ + obj.print(out); + out << std::flush; + return out; +} + +#endif // __CPU_RUBYTEST_CHECKTABLE_HH__ diff --git a/src/cpu/testers/rubytest/RubyTester.cc b/src/cpu/testers/rubytest/RubyTester.cc new file mode 100644 index 000000000..516d6ae40 --- /dev/null +++ b/src/cpu/testers/rubytest/RubyTester.cc @@ -0,0 +1,195 @@ +/* + * Copyright (c) 1999-2008 Mark D. Hill and David A. Wood + * Copyright (c) 2009 Advanced Micro Devices, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "cpu/testers/rubytest/Check.hh" +#include "cpu/testers/rubytest/RubyTester.hh" +#include "mem/ruby/common/Global.hh" +#include "mem/ruby/common/SubBlock.hh" +#include "mem/ruby/eventqueue/RubyEventQueue.hh" +#include "mem/ruby/system/System.hh" +#include "sim/sim_exit.hh" + +RubyTester::RubyTester(const Params *p) + : MemObject(p), checkStartEvent(this), + m_checks_to_complete(p->checks_to_complete), + m_deadlock_threshold(p->deadlock_threshold), + m_wakeup_frequency(p->wakeup_frequency) +{ + m_checks_completed = 0; + + // add the check start event to the event queue + schedule(checkStartEvent, 1); +} + +RubyTester::~RubyTester() +{ + delete m_checkTable_ptr; + for (int i = 0; i < ports.size(); i++) + delete ports[i]; +} + +void +RubyTester::init() +{ + assert(ports.size() > 0); + + m_last_progress_vector.resize(ports.size()); + for (int i = 0; i < m_last_progress_vector.size(); i++) { + m_last_progress_vector[i] = 0; + } + + m_num_cpu_sequencers = ports.size(); + + m_checkTable_ptr = new CheckTable(m_num_cpu_sequencers, this); +} + +Port * +RubyTester::getPort(const std::string &if_name, int idx) +{ + if (if_name != "cpuPort") { + panic("RubyTester::getPort: unknown port %s requested", if_name); + } + + if (idx >= (int)ports.size()) { + ports.resize(idx + 1); + } + + if (ports[idx] != NULL) { + panic("RubyTester::getPort: port %d already assigned", idx); + } + + CpuPort *port = new CpuPort(csprintf("%s-port%d", name(), idx), this, idx); + + ports[idx] = port; + return port; +} + +Tick +RubyTester::CpuPort::recvAtomic(PacketPtr pkt) +{ + panic("RubyTester::CpuPort::recvAtomic() not implemented!\n"); + return 0; +} + +bool +RubyTester::CpuPort::recvTiming(PacketPtr pkt) +{ + // retrieve the subblock and call hitCallback + RubyTester::SenderState* senderState = + safe_cast(pkt->senderState); + SubBlock* subblock = senderState->subBlock; + assert(subblock != NULL); + + // pop the sender state from the packet + pkt->senderState = senderState->saved; + + tester->hitCallback(idx, subblock); + + // Now that the tester has completed, delete the senderState + // (includes sublock) and the packet, then return + delete senderState; + delete pkt->req; + delete pkt; + return true; +} + +Port* +RubyTester::getCpuPort(int idx) +{ + assert(idx >= 0 && idx < ports.size()); + + return ports[idx]; +} + +void +RubyTester::hitCallback(NodeID proc, SubBlock* data) +{ + // Mark that we made progress + m_last_progress_vector[proc] = g_eventQueue_ptr->getTime(); + + DPRINTF(RubyTest, "completed request for proc: %d\n", proc); + DPRINTF(RubyTest, "addr: 0x%x, size: %d, data: ", + data->getAddress(), data->getSize()); + for (int byte = 0; byte < data->getSize(); byte++) { + DPRINTF(RubyTest, "%d", data->getByte(byte)); + } + DPRINTF(RubyTest, "\n"); + + // This tells us our store has 'completed' or for a load gives us + // back the data to make the check + Check* check_ptr = m_checkTable_ptr->getCheck(data->getAddress()); + assert(check_ptr != NULL); + check_ptr->performCallback(proc, data); +} + +void +RubyTester::wakeup() +{ + if (m_checks_completed < m_checks_to_complete) { + // Try to perform an action or check + Check* check_ptr = m_checkTable_ptr->getRandomCheck(); + assert(check_ptr != NULL); + check_ptr->initiate(); + + checkForDeadlock(); + + schedule(checkStartEvent, curTick + m_wakeup_frequency); + } else { + exitSimLoop("Ruby Tester completed"); + } +} + +void +RubyTester::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]) > + m_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); + ERROR_MSG("Deadlock detected."); + } + } +} + +void +RubyTester::print(std::ostream& out) const +{ + out << "[RubyTester]" << std::endl; +} + +RubyTester * +RubyTesterParams::create() +{ + return new RubyTester(this); +} diff --git a/src/cpu/testers/rubytest/RubyTester.hh b/src/cpu/testers/rubytest/RubyTester.hh new file mode 100644 index 000000000..53341bce9 --- /dev/null +++ b/src/cpu/testers/rubytest/RubyTester.hh @@ -0,0 +1,148 @@ +/* + * Copyright (c) 1999-2008 Mark D. Hill and David A. Wood + * Copyright (c) 2009 Advanced Micro Devices, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __CPU_RUBYTEST_RUBYTESTER_HH__ +#define __CPU_RUBYTEST_RUBYTESTER_HH__ + +#include +#include +#include + +#include "cpu/testers/rubytest/CheckTable.hh" +#include "mem/mem_object.hh" +#include "mem/packet.hh" +#include "mem/ruby/common/DataBlock.hh" +#include "mem/ruby/common/Global.hh" +#include "mem/ruby/common/SubBlock.hh" +#include "mem/ruby/system/RubyPort.hh" +#include "params/RubyTester.hh" + +class RubyTester : public MemObject +{ + public: + class CpuPort : public SimpleTimingPort + { + private: + RubyTester *tester; + + public: + CpuPort(const std::string &_name, RubyTester *_tester, int _idx) + : SimpleTimingPort(_name, _tester), tester(_tester), idx(_idx) + {} + + int idx; + + protected: + virtual bool recvTiming(PacketPtr pkt); + virtual Tick recvAtomic(PacketPtr pkt); + }; + + struct SenderState : public Packet::SenderState + { + SubBlock* subBlock; + Packet::SenderState *saved; + + SenderState(Address addr, int size, + Packet::SenderState *sender_state = NULL) + : saved(sender_state) + { + subBlock = new SubBlock(addr, size); + } + + ~SenderState() + { + delete subBlock; + } + }; + + typedef RubyTesterParams Params; + RubyTester(const Params *p); + ~RubyTester(); + + virtual Port *getPort(const std::string &if_name, int idx = -1); + + Port* getCpuPort(int idx); + + virtual void init(); + + void wakeup(); + + void incrementCheckCompletions() { m_checks_completed++; } + + void printStats(std::ostream& out) const {} + void clearStats() {} + void printConfig(std::ostream& out) const {} + + void print(std::ostream& out) const; + + protected: + class CheckStartEvent : public Event + { + private: + RubyTester *tester; + + public: + CheckStartEvent(RubyTester *_tester) + : Event(CPU_Tick_Pri), tester(_tester) + {} + void process() { tester->wakeup(); } + virtual const char *description() const { return "RubyTester tick"; } + }; + + CheckStartEvent checkStartEvent; + + private: + void hitCallback(NodeID proc, SubBlock* data); + + void checkForDeadlock(); + + // Private copy constructor and assignment operator + RubyTester(const RubyTester& obj); + RubyTester& operator=(const RubyTester& obj); + + CheckTable* m_checkTable_ptr; + std::vector