/* * Copyright (c) 1999-2008 Mark D. Hill and David A. Wood * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer; * redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution; * neither the name of the copyright holders nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * $Id$ * */ #include "Global.hh" #include "System.hh" #include "DeterministicDriver.hh" #include "EventQueue.hh" #include "SpecifiedGenerator.hh" #include "DetermGETXGenerator.hh" #include "DetermInvGenerator.hh" #include "DetermSeriesGETSGenerator.hh" #include "SubBlock.hh" #include "Chip.hh" DeterministicDriver::DeterministicDriver(System* sys_ptr) { if (g_SIMICS) { ERROR_MSG("g_SIMICS should not be defined."); } m_finish_time = 0; m_last_issue = -11; m_done_counter = 0; m_loads_completed = 0; m_stores_completed = 0; m_numCompletionsPerNode = g_NUM_COMPLETIONS_BEFORE_PASS; m_last_progress_vector.setSize(RubyConfig::numberOfProcessors()); for (int i=0; ischeduleEvent(this, 1); } DeterministicDriver::~DeterministicDriver() { for (int i=0; iperformCallback(proc, data); // Mark that we made progress m_last_progress_vector[proc] = g_eventQueue_ptr->getTime(); } bool DeterministicDriver::isStoreReady(NodeID node) { return isAddrReady(node, m_store_vector); } bool DeterministicDriver::isStoreReady(NodeID node, Address addr) { return isAddrReady(node, m_store_vector, addr); } bool DeterministicDriver::isLoadReady(NodeID node) { return isAddrReady(node, m_load_vector); } bool DeterministicDriver::isLoadReady(NodeID node, Address addr) { return isAddrReady(node, m_load_vector, addr); } // searches for any address in the addr_vector bool DeterministicDriver::isAddrReady(NodeID node, Vector addr_vector) { for (int i=0; i= m_numCompletionsPerNode*node) && // is this node next (g_eventQueue_ptr->getTime() >= m_last_issue + 10)) { // controll rate of requests return true; } } return false; } // test for a particular addr bool DeterministicDriver::isAddrReady(NodeID node, Vector addr_vector, Address addr) { int addr_number = addr.getAddress()/RubyConfig::dataBlockBytes(); ASSERT ((addr_number >= 0) && (addr_number < addr_vector.size())); if (((addr_vector[addr_number]+1)%RubyConfig::numberOfProcessors() == node) && (m_loads_completed+m_stores_completed >= m_numCompletionsPerNode*node) && // is this node next (g_eventQueue_ptr->getTime() >= m_last_issue + 10)) { // controll rate of requests return true; } else { return false; } } void DeterministicDriver::loadCompleted(NodeID node, Address addr) { m_loads_completed++; setNextAddr(node, addr, m_load_vector); } void DeterministicDriver::storeCompleted(NodeID node, Address addr) { m_stores_completed++; setNextAddr(node, addr, m_store_vector); } void DeterministicDriver::setNextAddr(NodeID node, Address addr, Vector& addr_vector) { // mark the addr vector that this proc was the last to use the particular address int addr_number = addr.getAddress()/RubyConfig::dataBlockBytes(); addr_vector[addr_number] = node; } Address DeterministicDriver::getNextLoadAddr(NodeID node) { return getNextAddr(node, m_load_vector); } Address DeterministicDriver::getNextStoreAddr(NodeID node) { return getNextAddr(node, m_store_vector); } Address DeterministicDriver::getNextAddr(NodeID node, Vector addr_vector) { // This method deterministically picks the next addr the node should acquirer // The addrs cycle through according to NodeID 0->1->...->lastID->0... Address addr; // should only be called if we know a addr is ready for the node ASSERT(isAddrReady(node, addr_vector)); for (int addr_number=0; addr_number0; addr_number--) { // is this node next in line for the addr if (((addr_vector[addr_number]+1)%RubyConfig::numberOfProcessors()) == node) { // One addr per cache line addr.setAddress(addr_number * RubyConfig::dataBlockBytes()); } } m_last_issue = g_eventQueue_ptr->getTime(); return addr; } void DeterministicDriver::reportDone() { m_done_counter++; if ((m_done_counter == RubyConfig::numberOfProcessors())) { //|| (m_done_counter == g_tester_length)) { m_finish_time = g_eventQueue_ptr->getTime(); } } void DeterministicDriver::recordLoadLatency(Time time) { m_load_latency.add(time); } void DeterministicDriver::recordStoreLatency(Time time) { m_store_latency.add(time); } void DeterministicDriver::wakeup() { // checkForDeadlock(); if (m_done_counter < RubyConfig::numberOfProcessors()) { g_eventQueue_ptr->scheduleEvent(this, g_DEADLOCK_THRESHOLD); } } void DeterministicDriver::checkForDeadlock() { int size = m_last_progress_vector.size(); Time current_time = g_eventQueue_ptr->getTime(); for (int processor=0; processor g_DEADLOCK_THRESHOLD) { WARN_EXPR(processor); Sequencer* seq_ptr = g_system_ptr->getChip(processor/RubyConfig::numberOfProcsPerChip())->getSequencer(processor%RubyConfig::numberOfProcsPerChip()); assert(seq_ptr != NULL); // if (seq_ptr->isRequestPending()) { // WARN_EXPR(seq_ptr->pendingAddress()); // } WARN_EXPR(current_time); WARN_EXPR(m_last_progress_vector[processor]); WARN_EXPR(current_time - m_last_progress_vector[processor]); ERROR_MSG("Deadlock detected."); } } } void DeterministicDriver::printStats(ostream& out) const { out << endl; out << "DeterministicDriver Stats" << endl; out << "---------------------" << endl; out << "finish_time: " << m_finish_time << endl; out << "load_latency: " << m_load_latency << endl; out << "store_latency: " << m_store_latency << endl; } void DeterministicDriver::print(ostream& out) const { }