summaryrefslogtreecommitdiff
path: root/src/mem/ruby/tester/SyntheticDriver.cc
diff options
context:
space:
mode:
Diffstat (limited to 'src/mem/ruby/tester/SyntheticDriver.cc')
-rw-r--r--src/mem/ruby/tester/SyntheticDriver.cc286
1 files changed, 286 insertions, 0 deletions
diff --git a/src/mem/ruby/tester/SyntheticDriver.cc b/src/mem/ruby/tester/SyntheticDriver.cc
new file mode 100644
index 000000000..f19baa202
--- /dev/null
+++ b/src/mem/ruby/tester/SyntheticDriver.cc
@@ -0,0 +1,286 @@
+
+/*
+ * Copyright (c) 1999-2008 Mark D. Hill and David A. Wood
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * $Id$
+ *
+ */
+
+#include "mem/ruby/common/Global.hh"
+#include "mem/ruby/system/System.hh"
+#include "mem/ruby/tester/SyntheticDriver.hh"
+#include "mem/ruby/eventqueue/RubyEventQueue.hh"
+#include "mem/ruby/tester/RequestGenerator.hh"
+#include "mem/ruby/common/SubBlock.hh"
+#include "mem/protocol/Chip.hh"
+
+SyntheticDriver::SyntheticDriver(RubySystem* sys_ptr)
+{
+ m_finish_time = 0;
+ m_done_counter = 0;
+
+ m_last_progress_vector.setSize(RubyConfig::numberOfProcessors());
+ for (int i=0; i<m_last_progress_vector.size(); i++) {
+ m_last_progress_vector[i] = 0;
+ }
+
+ m_lock_vector.setSize(g_synthetic_locks);
+ for (int i=0; i<m_lock_vector.size(); i++) {
+ m_lock_vector[i] = -1; // No processor last held it
+ }
+
+ m_request_generator_vector.setSize(RubyConfig::numberOfProcessors());
+ for (int i=0; i<m_request_generator_vector.size(); i++) {
+ if(XACT_MEMORY){
+ //m_request_generator_vector[i] = new XactRequestGenerator(i, *this);
+ } else {
+ m_request_generator_vector[i] = new RequestGenerator(i, *this);
+ }
+ }
+
+ // add the tester consumer to the global event queue
+ g_eventQueue_ptr->scheduleEvent(this, 1);
+}
+
+SyntheticDriver::~SyntheticDriver()
+{
+ for (int i=0; i<m_last_progress_vector.size(); i++) {
+ delete m_request_generator_vector[i];
+ }
+}
+
+void
+SyntheticDriver::hitCallback(Packet * pkt)
+{
+ NodeID proc = pkt->req->contextId();
+ SubBlock data(Address(pkt->getAddr()), pkt->req->getSize());
+ if (pkt->hasData()) {
+ for (int i = 0; i < pkt->req->getSize(); i++) {
+ data.setByte(i, *(pkt->getPtr<uint8>()+i));
+ }
+ }
+ m_request_generator_vector[proc]->performCallback(proc, data);
+ m_last_progress_vector[proc] = g_eventQueue_ptr->getTime();
+}
+
+void SyntheticDriver::abortCallback(NodeID proc, SubBlock& data, CacheRequestType type, int thread)
+{
+ //cout << "SyntheticDriver::abortCallback" << endl;
+ DEBUG_EXPR(TESTER_COMP, MedPrio, data);
+
+ if(XACT_MEMORY){
+ //XactRequestGenerator* reqGen = static_cast<XactRequestGenerator*>(m_request_generator_vector[proc]);
+ //reqGen->abortTransaction();
+ //reqGen->performCallback(proc, data);
+ } else {
+ m_request_generator_vector[proc]->performCallback(proc, data);
+ }
+
+ // Mark that we made progress
+ m_last_progress_vector[proc] = g_eventQueue_ptr->getTime();
+}
+
+// For Transactional Memory
+/*
+// called whenever we send a nack
+void SyntheticDriver::notifySendNack( int proc, const Address & addr, uint64 remote_timestamp, const MachineID & remote_id ){
+ if(XACT_MEMORY){
+ //XactRequestGenerator* reqGen = static_cast<XactRequestGenerator*>(m_request_generator_vector[proc]);
+ //reqGen->notifySendNack(addr, remote_timestamp, remote_id);
+ }
+ else{
+ cout << "notifySendNack NOT USING TM" << endl;
+ ASSERT(0);
+ }
+}
+
+// called whenever we receive a NACK
+// Either for a demand request or log store
+void SyntheticDriver::notifyReceiveNack( int proc, const Address & addr, uint64 remote_timestamp, const MachineID & remote_id ){
+ if(XACT_MEMORY){
+ //XactRequestGenerator* reqGen = static_cast<XactRequestGenerator*>(m_request_generator_vector[proc]);
+ //reqGen->notifyReceiveNack(addr, remote_timestamp, remote_id);
+ }
+ else{
+ cout << "notifyReceiveNack NOT USING TM" << endl;
+ ASSERT(0);
+ }
+}
+
+// called whenever we received ALL the NACKs. Take abort or retry action here
+void SyntheticDriver::notifyReceiveNackFinal(int proc, const Address & addr){
+ if(XACT_MEMORY){
+ //XactRequestGenerator* reqGen = static_cast<XactRequestGenerator*>(m_request_generator_vector[proc]);
+ //reqGen->notifyReceiveNackFinal(addr);
+ }
+ else{
+ ASSERT(0);
+ }
+}
+
+// called during abort handling
+// void SyntheticDriver::notifyAbortStart( const Address & handlerPC ){
+
+// }
+
+// void SyntheticDriver::notifyAbortComplete( const Address & newPC ){
+
+// }
+*/
+
+Address SyntheticDriver::pickAddress(NodeID node)
+{
+ // This methods picks a random lock that we were NOT that last
+ // processor to acquire. Why? Without this change 2 and 4
+ // processor runs, the odds of having the lock in your cache in
+ // read/write state is 50% or 25%, respectively. This effect can
+ // make our 'throughput per processor' results look too strange.
+
+ Address addr;
+ // FIXME - make this a parameter of the workload
+ int lock_number = 0;
+ int counter = 0;
+ while (1) {
+ // Pick a random lock
+ lock_number = random() % m_lock_vector.size();
+
+ // Were we the last to acquire the lock?
+ if (m_lock_vector[lock_number] != node) {
+ break;
+ }
+
+ // Don't keep trying forever, since if there is only one lock, we're always the last to try to obtain the lock
+ counter++;
+ if (counter > 10) {
+ break;
+ }
+ }
+
+ // We're going to acquire it soon, so we can update the last
+ // processor to hold the lock at this time
+ m_lock_vector[lock_number] = node;
+
+ // One lock per cache line
+ addr.setAddress(lock_number * RubyConfig::dataBlockBytes());
+ return addr;
+}
+
+void SyntheticDriver::reportDone()
+{
+ m_done_counter++;
+ if (m_done_counter == RubyConfig::numberOfProcessors()) {
+ m_finish_time = g_eventQueue_ptr->getTime();
+ }
+}
+
+void SyntheticDriver::recordTestLatency(Time time)
+{
+ m_test_latency.add(time);
+}
+
+void SyntheticDriver::recordSwapLatency(Time time)
+{
+ m_swap_latency.add(time);
+}
+
+void SyntheticDriver::recordReleaseLatency(Time time)
+{
+ m_release_latency.add(time);
+}
+
+void SyntheticDriver::wakeup()
+{
+ // checkForDeadlock();
+ if (m_done_counter < RubyConfig::numberOfProcessors()) {
+ g_eventQueue_ptr->scheduleEvent(this, g_DEADLOCK_THRESHOLD);
+ }
+}
+
+void SyntheticDriver::checkForDeadlock()
+{
+ int size = m_last_progress_vector.size();
+ Time current_time = g_eventQueue_ptr->getTime();
+ for (int processor=0; processor<size; processor++) {
+ if ((current_time - m_last_progress_vector[processor]) > g_DEADLOCK_THRESHOLD) {
+ WARN_EXPR(processor);
+#ifndef NDEBUG
+ Sequencer* seq_ptr = g_system_ptr->getChip(processor/RubyConfig::numberOfProcsPerChip())->getSequencer(processor%RubyConfig::numberOfProcsPerChip());
+#endif
+ assert(seq_ptr != NULL);
+ // if (seq_ptr->isRequestPending()) {
+ // WARN_EXPR(seq_ptr->pendingAddress());
+ // }
+ WARN_EXPR(current_time);
+ WARN_EXPR(m_last_progress_vector[processor]);
+ WARN_EXPR(current_time - m_last_progress_vector[processor]);
+ ERROR_MSG("Deadlock detected.");
+ }
+ }
+}
+
+integer_t SyntheticDriver::readPhysicalMemory(int procID, physical_address_t address,
+ int len ){
+ char buffer[8];
+ ASSERT(len <= 8);
+ Sequencer* seq = g_system_ptr->getChip(procID/RubyConfig::numberOfProcsPerChip())->getSequencer(procID%RubyConfig::numberOfProcsPerChip());
+ assert(seq != NULL);
+ bool found = seq->getRubyMemoryValue(Address(address), buffer, len );
+ ASSERT(found);
+ return *((integer_t *) buffer);
+}
+
+void SyntheticDriver::writePhysicalMemory( int procID, physical_address_t address,
+ integer_t value, int len ){
+ char buffer[8];
+ ASSERT(len <= 8);
+
+ memcpy(buffer, (const void*) &value, len);
+ DEBUG_EXPR(TESTER_COMP, MedPrio, "");
+ Sequencer* seq = g_system_ptr->getChip(procID/RubyConfig::numberOfProcsPerChip())->getSequencer(procID%RubyConfig::numberOfProcsPerChip());
+ assert(seq != NULL);
+ bool found = seq->setRubyMemoryValue(Address(address), buffer, len );
+ ASSERT(found);
+ //return found;
+}
+
+void SyntheticDriver::printStats(ostream& out) const
+{
+ out << endl;
+ out << "SyntheticDriver Stats" << endl;
+ out << "---------------------" << endl;
+
+ out << "synthetic_finish_time: " << m_finish_time << endl;
+ out << "test_latency: " << m_test_latency << endl;
+ out << "swap_latency: " << m_swap_latency << endl;
+ out << "release_latency: " << m_release_latency << endl;
+}
+
+void SyntheticDriver::print(ostream& out) const
+{
+}