ruby: Remove transactional access types (e.g. LD_XACT) from CacheRequestType
1. Modified enumeration 2. Also modified profiler 3. Remove transactions from Tester 4. Edited XACT_MEM out of Synthetic Driver
This commit is contained in:
parent
9f34659c52
commit
b271090923
|
@ -131,12 +131,6 @@ enumeration(CacheRequestType, desc="...", default="CacheRequestType_NULL") {
|
||||||
IO, desc="I/O";
|
IO, desc="I/O";
|
||||||
REPLACEMENT, desc="Replacement";
|
REPLACEMENT, desc="Replacement";
|
||||||
COMMIT, desc="Commit version";
|
COMMIT, desc="Commit version";
|
||||||
LD_XACT, desc="Transactional Load";
|
|
||||||
LDX_XACT, desc="Transactional Load-Intend-To-Modify";
|
|
||||||
ST_XACT, desc="Transactional Store";
|
|
||||||
BEGIN_XACT, desc="Begin Transaction";
|
|
||||||
COMMIT_XACT, desc="Commit Transaction";
|
|
||||||
ABORT_XACT, desc="Abort Transaction";
|
|
||||||
NULL, desc="Invalid request type";
|
NULL, desc="Invalid request type";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -162,12 +156,6 @@ enumeration(GenericRequestType, desc="...", default="GenericRequestType_NULL") {
|
||||||
WB_ACK, desc="WriteBack ack";
|
WB_ACK, desc="WriteBack ack";
|
||||||
EXE_ACK, desc="Execlusive ack";
|
EXE_ACK, desc="Execlusive ack";
|
||||||
COMMIT, desc="Commit version";
|
COMMIT, desc="Commit version";
|
||||||
LD_XACT, desc="Transactional Load";
|
|
||||||
LDX_XACT, desc="Transactional Load-Intend-Modify";
|
|
||||||
ST_XACT, desc="Transactional Store";
|
|
||||||
BEGIN_XACT, desc="Begin Transaction";
|
|
||||||
COMMIT_XACT, desc="Commit Transaction";
|
|
||||||
ABORT_XACT, desc="Abort Transaction";
|
|
||||||
NULL, desc="null request type";
|
NULL, desc="null request type";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1006,15 +1006,6 @@ GenericRequestType Profiler::CacheRequestType_to_GenericRequestType(const CacheR
|
||||||
case CacheRequestType_IFETCH:
|
case CacheRequestType_IFETCH:
|
||||||
return GenericRequestType_IFETCH;
|
return GenericRequestType_IFETCH;
|
||||||
break;
|
break;
|
||||||
case CacheRequestType_LD_XACT:
|
|
||||||
return GenericRequestType_LD_XACT;
|
|
||||||
break;
|
|
||||||
case CacheRequestType_LDX_XACT:
|
|
||||||
return GenericRequestType_LDX_XACT;
|
|
||||||
break;
|
|
||||||
case CacheRequestType_ST_XACT:
|
|
||||||
return GenericRequestType_ST_XACT;
|
|
||||||
break;
|
|
||||||
case CacheRequestType_NULL:
|
case CacheRequestType_NULL:
|
||||||
return GenericRequestType_NULL;
|
return GenericRequestType_NULL;
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -1,263 +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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "mem/ruby/profiler/XactProfiler.hh"
|
|
||||||
#include "mem/protocol/CacheMsg.hh"
|
|
||||||
#include "mem/gems_common/Map.hh"
|
|
||||||
#include "mem/ruby/common/Debug.hh"
|
|
||||||
#include "mem/protocol/MachineType.hh"
|
|
||||||
#include "TransactionInterfaceManager.hh"
|
|
||||||
#include "mem/ruby/common/Driver.hh"
|
|
||||||
#include "interface.hh"
|
|
||||||
|
|
||||||
extern std::ostream * debug_cout_ptr;
|
|
||||||
|
|
||||||
XactProfiler::XactProfiler()
|
|
||||||
{
|
|
||||||
int num_processors = RubyConfig::numberOfProcessors() * RubyConfig::numberofSMTThreads();
|
|
||||||
|
|
||||||
m_xactTransCycles = new long long int[num_processors];
|
|
||||||
m_xactStallTransCycles = new long long int[num_processors];
|
|
||||||
m_xactStallNonTransCycles = new long long int[num_processors];
|
|
||||||
m_xactAbortingCycles = new long long int[num_processors];
|
|
||||||
m_xactCommitingCycles = new long long int[num_processors];
|
|
||||||
m_xactBackoffCycles = new long long int[num_processors];
|
|
||||||
m_BarrierCycles = new long long int[num_processors];
|
|
||||||
|
|
||||||
m_xactGoodTransCycles = new long long int[num_processors];
|
|
||||||
m_xactNonTransCycles = new long long int[num_processors];
|
|
||||||
|
|
||||||
m_xactTimedCycles = new long long int[num_processors];
|
|
||||||
m_xactBeginTimer = new long long int[num_processors];
|
|
||||||
|
|
||||||
clearStats();
|
|
||||||
}
|
|
||||||
|
|
||||||
XactProfiler::~XactProfiler()
|
|
||||||
{
|
|
||||||
delete [] m_xactTransCycles;
|
|
||||||
delete [] m_xactStallTransCycles;
|
|
||||||
delete [] m_xactStallNonTransCycles;
|
|
||||||
delete [] m_xactAbortingCycles;
|
|
||||||
delete [] m_xactBackoffCycles;
|
|
||||||
|
|
||||||
delete [] m_xactGoodTransCycles;
|
|
||||||
delete [] m_xactNonTransCycles;
|
|
||||||
|
|
||||||
delete [] m_xactTimedCycles;
|
|
||||||
delete [] m_xactBeginTimer;
|
|
||||||
}
|
|
||||||
|
|
||||||
void XactProfiler::printConfig(ostream& out) const
|
|
||||||
{
|
|
||||||
out << endl;
|
|
||||||
out << "XactProfiler Configuration" << endl;
|
|
||||||
out << "----------------------" << endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
void XactProfiler::print(ostream& out) const
|
|
||||||
{
|
|
||||||
out << "[XactProfiler]";
|
|
||||||
}
|
|
||||||
|
|
||||||
void XactProfiler::printStats(ostream& out, bool short_stats)
|
|
||||||
{
|
|
||||||
int num_processors = RubyConfig::numberOfProcessors() * RubyConfig::numberofSMTThreads();
|
|
||||||
out << endl;
|
|
||||||
|
|
||||||
out << "XactProfiler Stats" << endl;
|
|
||||||
out << "--------------" << endl;
|
|
||||||
|
|
||||||
if (max_hashFunction >= 0){
|
|
||||||
out << "Hash values distribution" << endl;
|
|
||||||
out << "------------------------" << endl;
|
|
||||||
for(int i = 0; i <= max_hashFunction; i++){
|
|
||||||
out << "Hash function " << i << ": " << m_hashProfile[i] << endl;
|
|
||||||
}
|
|
||||||
out << endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
out << "xact_cycle_breakdown" << endl;
|
|
||||||
out << "--------------------" << endl;
|
|
||||||
long long int total_trans_cycles = 0;
|
|
||||||
long long int total_aborting_trans_cycles = 0;
|
|
||||||
long long int total_commiting_trans_cycles = 0;
|
|
||||||
long long int total_backoff_trans_cycles = 0;
|
|
||||||
long long int total_stall_trans_cycles = 0;
|
|
||||||
long long int total_stall_nontrans_cycles = 0;
|
|
||||||
long long int total_barrier_cycles = 0;
|
|
||||||
|
|
||||||
long long int total_good_trans_cycles = 0;
|
|
||||||
long long int total_nontrans_cycles = 0;
|
|
||||||
|
|
||||||
long long int total_timed_cycles = 0;
|
|
||||||
|
|
||||||
for(int i=0; i < num_processors; ++i){
|
|
||||||
if (!short_stats){
|
|
||||||
out << "xact_trans_cycles_processor_" << i << ": " << m_xactTransCycles[i] << endl;
|
|
||||||
out << "xact_aborting_cycles_processor_" << i << ": " << m_xactAbortingCycles[i] << endl;
|
|
||||||
out << "xact_barrier_cycles_processor_" << i << ": " << m_BarrierCycles[i] << endl;
|
|
||||||
out << "xact_backoff_cycles_processor_" << i << ": " << m_xactBackoffCycles[i] << endl;
|
|
||||||
out << "xact_stall_trans_cycles_processor_" << i << ": " << m_xactStallTransCycles[i] << endl;
|
|
||||||
out << "xact_nontrans_cycles_processor_" << i << ": " << m_xactNonTransCycles[i] << endl;
|
|
||||||
out << "xact_stall_nontrans_cycles_processor_" << i << ": " << m_xactStallNonTransCycles[i] << endl;
|
|
||||||
out << "timed_cycles_processor_" << i << ": " << m_xactTimedCycles[i] << endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
total_trans_cycles += m_xactTransCycles[i];
|
|
||||||
total_stall_trans_cycles += m_xactStallTransCycles[i];
|
|
||||||
total_aborting_trans_cycles += m_xactAbortingCycles[i];
|
|
||||||
total_commiting_trans_cycles += m_xactCommitingCycles[i];
|
|
||||||
total_backoff_trans_cycles += m_xactBackoffCycles[i];
|
|
||||||
total_barrier_cycles += m_BarrierCycles[i];
|
|
||||||
total_nontrans_cycles += m_xactNonTransCycles[i];
|
|
||||||
total_good_trans_cycles += m_xactGoodTransCycles[i];
|
|
||||||
total_stall_nontrans_cycles += m_xactStallNonTransCycles[i];
|
|
||||||
total_timed_cycles += m_xactTimedCycles[i];
|
|
||||||
|
|
||||||
}
|
|
||||||
out << endl;
|
|
||||||
out << " XACT CYCLE BREAKDOWN " << endl;
|
|
||||||
out << " XACT_BREAKDOWN_NON_TRANS_CYCLES: " << total_nontrans_cycles << endl;
|
|
||||||
out << " XACT_BREAKDOWN_TRANS_CYCLES: " << total_trans_cycles << endl;
|
|
||||||
out << " XACT_BREAKDOWN_GOOD_TRANS_CYCLES: " << total_good_trans_cycles << endl;
|
|
||||||
out << " XACT_BREAKDOWN_ABORTING_CYCLES: " << total_aborting_trans_cycles << endl;
|
|
||||||
out << " XACT_BREAKDOWN_COMMITING_CYCLES: " << total_commiting_trans_cycles << endl;
|
|
||||||
out << " XACT_BREAKDOWN_BACKOFF_CYCLES: " << total_backoff_trans_cycles << endl;
|
|
||||||
out << " XACT_BREAKDOWN_BARRIER_CYCLES: " << total_barrier_cycles << endl;
|
|
||||||
out << " XACT_BREAKDOWN_STALL_CYCLES: " << total_stall_trans_cycles << endl;
|
|
||||||
out << endl;
|
|
||||||
out << " XACT_TIMED_CYCLES: " << total_timed_cycles << endl;
|
|
||||||
out << endl;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
void XactProfiler::clearStats()
|
|
||||||
{
|
|
||||||
int num_processors = RubyConfig::numberOfProcessors() * RubyConfig::numberofSMTThreads();
|
|
||||||
for(int i=0; i < num_processors; ++i){
|
|
||||||
m_xactTransCycles[i] = 0;
|
|
||||||
m_xactStallTransCycles[i] = 0;
|
|
||||||
m_xactGoodTransCycles[i] = 0;
|
|
||||||
m_xactBackoffCycles[i] = 0;
|
|
||||||
m_xactAbortingCycles[i] = 0;
|
|
||||||
m_xactCommitingCycles[i] = 0;
|
|
||||||
m_xactNonTransCycles[i] = 0;
|
|
||||||
m_xactStallNonTransCycles[i] = 0;
|
|
||||||
m_BarrierCycles[i] = 0;
|
|
||||||
m_xactTimedCycles[i] = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
max_hashFunction = -1;
|
|
||||||
m_hashProfile.setSize(16);
|
|
||||||
for (int i = 0; i < 15; i++) {
|
|
||||||
m_hashProfile[i].clear();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void XactProfiler::profileTransCycles(int proc, int cycles){
|
|
||||||
m_xactTransCycles[proc] += cycles;
|
|
||||||
}
|
|
||||||
|
|
||||||
long long int XactProfiler::getTransCycles(int proc){
|
|
||||||
return m_xactTransCycles[proc];
|
|
||||||
}
|
|
||||||
|
|
||||||
void XactProfiler::profileStallTransCycles(int proc, int cycles){
|
|
||||||
m_xactStallTransCycles[proc] += cycles;
|
|
||||||
}
|
|
||||||
|
|
||||||
long long int XactProfiler::getStallTransCycles(int proc){
|
|
||||||
return m_xactStallTransCycles[proc];
|
|
||||||
}
|
|
||||||
|
|
||||||
void XactProfiler::profileGoodTransCycles(int proc, int cycles){
|
|
||||||
m_xactGoodTransCycles[proc] += cycles;
|
|
||||||
}
|
|
||||||
|
|
||||||
long long int XactProfiler::getGoodTransCycles(int proc){
|
|
||||||
return m_xactGoodTransCycles[proc];
|
|
||||||
}
|
|
||||||
|
|
||||||
void XactProfiler::profileAbortingTransCycles(int proc, int cycles){
|
|
||||||
m_xactAbortingCycles[proc] += cycles;
|
|
||||||
}
|
|
||||||
|
|
||||||
long long int XactProfiler::getAbortingTransCycles(int proc){
|
|
||||||
return m_xactAbortingCycles[proc];
|
|
||||||
}
|
|
||||||
|
|
||||||
void XactProfiler::profileCommitingTransCycles(int proc, int cycles){
|
|
||||||
m_xactCommitingCycles[proc] += cycles;
|
|
||||||
}
|
|
||||||
|
|
||||||
long long int XactProfiler::getCommitingTransCycles(int proc){
|
|
||||||
return m_xactCommitingCycles[proc];
|
|
||||||
}
|
|
||||||
|
|
||||||
void XactProfiler::profileBackoffTransCycles(int proc, int cycles){
|
|
||||||
m_xactBackoffCycles[proc] += cycles;
|
|
||||||
}
|
|
||||||
|
|
||||||
long long int XactProfiler::getBackoffTransCycles(int proc){
|
|
||||||
return m_xactBackoffCycles[proc];
|
|
||||||
}
|
|
||||||
|
|
||||||
void XactProfiler::profileStallNonTransCycles(int proc, int cycles){
|
|
||||||
m_xactStallNonTransCycles[proc] += cycles;
|
|
||||||
}
|
|
||||||
|
|
||||||
void XactProfiler::profileNonTransCycles(int proc, int cycles){
|
|
||||||
m_xactNonTransCycles[proc] += cycles;
|
|
||||||
}
|
|
||||||
|
|
||||||
long long int XactProfiler::getNonTransCycles(int proc){
|
|
||||||
return m_xactNonTransCycles[proc];
|
|
||||||
}
|
|
||||||
|
|
||||||
void XactProfiler::profileBarrierCycles(int proc, int cycles){
|
|
||||||
m_BarrierCycles[proc] += cycles;
|
|
||||||
}
|
|
||||||
|
|
||||||
long long int XactProfiler::getBarrierCycles(int proc){
|
|
||||||
return m_BarrierCycles[proc];
|
|
||||||
}
|
|
||||||
|
|
||||||
void XactProfiler::profileBeginTimer(int proc){
|
|
||||||
m_xactBeginTimer[proc] = (long long int) g_eventQueue_ptr->getTime();
|
|
||||||
}
|
|
||||||
|
|
||||||
void XactProfiler::profileEndTimer(int proc){
|
|
||||||
m_xactTimedCycles[proc] += (long long int) g_eventQueue_ptr->getTime() - m_xactBeginTimer[proc];
|
|
||||||
}
|
|
||||||
|
|
||||||
void XactProfiler::profileHashValue(int hashFunction, int hashValue){
|
|
||||||
if (hashFunction > max_hashFunction) max_hashFunction = hashFunction;
|
|
||||||
|
|
||||||
m_hashProfile[hashFunction].add(hashValue);
|
|
||||||
}
|
|
|
@ -1,125 +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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef XACTPROFILER_H
|
|
||||||
#define XACTPROFILER_H
|
|
||||||
|
|
||||||
#include "mem/ruby/common/Global.hh"
|
|
||||||
#include "mem/protocol/GenericMachineType.hh"
|
|
||||||
#include "mem/ruby/config/RubyConfig.hh"
|
|
||||||
#include "mem/ruby/common/Histogram.hh"
|
|
||||||
#include "mem/ruby/common/Consumer.hh"
|
|
||||||
#include "mem/protocol/AccessModeType.hh"
|
|
||||||
#include "mem/protocol/AccessType.hh"
|
|
||||||
#include "mem/ruby/system/NodeID.hh"
|
|
||||||
#include "mem/ruby/system/MachineID.hh"
|
|
||||||
#include "mem/protocol/PrefetchBit.hh"
|
|
||||||
#include "mem/ruby/common/Address.hh"
|
|
||||||
#include "mem/ruby/common/Set.hh"
|
|
||||||
#include "mem/protocol/CacheRequestType.hh"
|
|
||||||
#include "mem/protocol/GenericRequestType.hh"
|
|
||||||
|
|
||||||
template <class KEY_TYPE, class VALUE_TYPE> class Map;
|
|
||||||
|
|
||||||
class XactProfiler {
|
|
||||||
public:
|
|
||||||
// Constructors
|
|
||||||
XactProfiler();
|
|
||||||
|
|
||||||
// Destructor
|
|
||||||
~XactProfiler();
|
|
||||||
|
|
||||||
void printStats(ostream& out, bool short_stats=false);
|
|
||||||
void printShortStats(ostream& out) { printStats(out, true); }
|
|
||||||
void clearStats();
|
|
||||||
void printConfig(ostream& out) const;
|
|
||||||
|
|
||||||
void print(ostream& out) const;
|
|
||||||
|
|
||||||
void profileTransCycles(int proc, int cycles);
|
|
||||||
void profileNonTransCycles(int proc, int cycles);
|
|
||||||
void profileStallTransCycles(int proc, int cycles);
|
|
||||||
void profileStallNonTransCycles(int proc, int cycles);
|
|
||||||
void profileAbortingTransCycles(int proc, int cycles);
|
|
||||||
void profileCommitingTransCycles(int proc, int cycles);
|
|
||||||
void profileBarrierCycles(int proc, int cycles);
|
|
||||||
void profileBackoffTransCycles(int proc, int cycles);
|
|
||||||
void profileGoodTransCycles(int proc, int cycles);
|
|
||||||
|
|
||||||
void profileBeginTimer(int proc);
|
|
||||||
void profileEndTimer(int proc);
|
|
||||||
|
|
||||||
long long int getTransCycles(int proc_no);
|
|
||||||
long long int getGoodTransCycles(int proc_no);
|
|
||||||
long long int getStallTransCycles(int proc_no);
|
|
||||||
long long int getAbortingTransCycles(int proc_no);
|
|
||||||
long long int getCommitingTransCycles(int proc_no);
|
|
||||||
long long int getBackoffTransCycles(int proc_no);
|
|
||||||
long long int getNonTransCycles(int proc_no);
|
|
||||||
long long int getBarrierCycles(int proc_no);
|
|
||||||
|
|
||||||
void profileHashValue(int hashFunction, int hashValue);
|
|
||||||
|
|
||||||
private:
|
|
||||||
|
|
||||||
long long int * m_xactTransCycles;
|
|
||||||
long long int * m_xactStallTransCycles;
|
|
||||||
long long int * m_xactStallNonTransCycles;
|
|
||||||
long long int * m_xactAbortingCycles;
|
|
||||||
long long int * m_xactCommitingCycles;
|
|
||||||
long long int * m_xactBackoffCycles;
|
|
||||||
long long int * m_BarrierCycles;
|
|
||||||
|
|
||||||
long long int * m_xactGoodTransCycles;
|
|
||||||
long long int * m_xactNonTransCycles;
|
|
||||||
|
|
||||||
long long int * m_xactTimedCycles;
|
|
||||||
long long int * m_xactBeginTimer;
|
|
||||||
|
|
||||||
int max_hashFunction;
|
|
||||||
Vector<Histogram> m_hashProfile;
|
|
||||||
};
|
|
||||||
|
|
||||||
// Output operator declaration
|
|
||||||
ostream& operator<<(ostream& out, const XactProfiler& obj);
|
|
||||||
|
|
||||||
// ******************* Definitions *******************
|
|
||||||
|
|
||||||
// Output operator definition
|
|
||||||
extern inline
|
|
||||||
ostream& operator<<(ostream& out, const XactProfiler& obj)
|
|
||||||
{
|
|
||||||
obj.print(out);
|
|
||||||
out << flush;
|
|
||||||
return out;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif //XACTPROFILER_H
|
|
||||||
|
|
||||||
|
|
|
@ -36,11 +36,7 @@
|
||||||
#include "mem/ruby/system/System.hh"
|
#include "mem/ruby/system/System.hh"
|
||||||
#include "mem/ruby/tester/SyntheticDriver.hh"
|
#include "mem/ruby/tester/SyntheticDriver.hh"
|
||||||
#include "mem/ruby/eventqueue/RubyEventQueue.hh"
|
#include "mem/ruby/eventqueue/RubyEventQueue.hh"
|
||||||
//#ifndef XACT_MEM
|
|
||||||
#include "mem/ruby/tester/RequestGenerator.hh"
|
#include "mem/ruby/tester/RequestGenerator.hh"
|
||||||
//#endif
|
|
||||||
//#include "mem/ruby/tester/XactAbortRequestGenerator.hh"
|
|
||||||
//#include "mem/ruby/tester/XactRequestGenerator.hh"
|
|
||||||
#include "mem/ruby/common/SubBlock.hh"
|
#include "mem/ruby/common/SubBlock.hh"
|
||||||
#include "mem/protocol/Chip.hh"
|
#include "mem/protocol/Chip.hh"
|
||||||
|
|
||||||
|
@ -150,7 +146,6 @@ void SyntheticDriver::notifyReceiveNackFinal(int proc, const Address & addr){
|
||||||
//reqGen->notifyReceiveNackFinal(addr);
|
//reqGen->notifyReceiveNackFinal(addr);
|
||||||
}
|
}
|
||||||
else{
|
else{
|
||||||
cout << "notifyReceiveNackFinal NOT USING TM" << endl;
|
|
||||||
ASSERT(0);
|
ASSERT(0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,403 +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$
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifdef XACT_MEM
|
|
||||||
|
|
||||||
#include "mem/ruby/tester/XactAbortRequestGenerator.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"
|
|
||||||
#include "mem/ruby/tester/Instruction.hh"
|
|
||||||
#include "TransactionManager.hh"
|
|
||||||
|
|
||||||
//uint8 XactAbortRequestGenerator::testArray[MAX_ADDRESS];
|
|
||||||
//uint8 XactAbortRequestGenerator::dataArray[MAX_ADDRESS];
|
|
||||||
Vector<uint8> XactAbortRequestGenerator::testArray;
|
|
||||||
|
|
||||||
XactAbortRequestGenerator::XactAbortRequestGenerator(NodeID node, SyntheticDriver& driver) :
|
|
||||||
RequestGenerator(node, driver), m_driver(driver)
|
|
||||||
{
|
|
||||||
//DEBUG_EXPR(TESTER_COMP, MedPrio, "#### -- Creating XactAbortRequestGenerator\n");
|
|
||||||
cout << "#### -- Creating XactAbortRequestGenerator " << node << endl;
|
|
||||||
|
|
||||||
testArray.setSize(g_MEMORY_SIZE_BYTES);
|
|
||||||
assert(testArray.size() == g_MEMORY_SIZE_BYTES);
|
|
||||||
// Create instructions
|
|
||||||
m_instructions = new Instruction[XACT_LENGTH];
|
|
||||||
newTransaction();
|
|
||||||
|
|
||||||
m_xact_status = XactAbortRequestGeneratorStatus_Ready;
|
|
||||||
m_last_transition = 0;
|
|
||||||
m_node = node;
|
|
||||||
//pickAddress();
|
|
||||||
m_counter = 0;
|
|
||||||
m_register = 5;
|
|
||||||
m_pc = 0;
|
|
||||||
|
|
||||||
//for(int i=0; i<XACT_SIZE; ++i){
|
|
||||||
//testArray[i] = 64;
|
|
||||||
//}
|
|
||||||
|
|
||||||
//testArray = new uint8[XACT_SIZE];
|
|
||||||
//dataArray = new uint8[XACT_SIZE];
|
|
||||||
g_eventQueue_ptr->scheduleEvent(this, 1+(random() % 200));
|
|
||||||
}
|
|
||||||
|
|
||||||
void XactAbortRequestGenerator::newTransaction(){
|
|
||||||
int num_stores = 16;
|
|
||||||
int num_loads = XACT_LENGTH - num_stores - 2;
|
|
||||||
|
|
||||||
for(int i=0; i<XACT_LENGTH; ++i){
|
|
||||||
if (i == 0){
|
|
||||||
m_instructions[i].init(Opcode_BEGIN, Address(1));
|
|
||||||
} else if (i == XACT_LENGTH - 1){
|
|
||||||
m_instructions[i].init(Opcode_COMMIT, Address(1));
|
|
||||||
} else if (i < num_loads) {
|
|
||||||
physical_address_t address = i % XACT_SIZE;
|
|
||||||
ASSERT(address < XACT_SIZE);
|
|
||||||
|
|
||||||
int selectOpcode = random() % 2;
|
|
||||||
Opcode op;
|
|
||||||
switch(selectOpcode){
|
|
||||||
case 0:
|
|
||||||
op = Opcode_LD;
|
|
||||||
break;
|
|
||||||
case 1:
|
|
||||||
op = Opcode_INC;
|
|
||||||
break;
|
|
||||||
};
|
|
||||||
m_instructions[i].init(op, Address(address));
|
|
||||||
} else {
|
|
||||||
physical_address_t address = i - num_loads;
|
|
||||||
ASSERT(address < XACT_SIZE);
|
|
||||||
Opcode op = Opcode_ST;
|
|
||||||
m_instructions[i].init(op, Address(address));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
XactAbortRequestGenerator::~XactAbortRequestGenerator()
|
|
||||||
{
|
|
||||||
delete m_instructions;
|
|
||||||
}
|
|
||||||
|
|
||||||
void XactAbortRequestGenerator::wakeup()
|
|
||||||
{
|
|
||||||
assert(m_xact_status == XactAbortRequestGeneratorStatus_Ready || m_xact_status == XactAbortRequestGeneratorStatus_Aborted);
|
|
||||||
m_xact_status = XactAbortRequestGeneratorStatus_Blocked;
|
|
||||||
DEBUG_EXPR(TESTER_COMP, MedPrio, m_node);
|
|
||||||
DEBUG_EXPR(TESTER_COMP, MedPrio, m_xact_status);
|
|
||||||
|
|
||||||
m_last_transition = g_eventQueue_ptr->getTime();
|
|
||||||
execute();
|
|
||||||
}
|
|
||||||
|
|
||||||
void XactAbortRequestGenerator::execute(){
|
|
||||||
assert(m_pc >= 0 && m_pc < XACT_LENGTH);
|
|
||||||
Instruction current = m_instructions[m_pc];
|
|
||||||
//cout << " " << m_node << " executing pc: " << m_pc;
|
|
||||||
switch (current.getOpcode()){
|
|
||||||
case Opcode_BEGIN:
|
|
||||||
//cout << " -- begin.";
|
|
||||||
initiateBeginTransaction();
|
|
||||||
break;
|
|
||||||
case Opcode_LD:
|
|
||||||
//cout << " -- load: " << current.getAddress();
|
|
||||||
initiateLoad(current.getAddress());
|
|
||||||
break;
|
|
||||||
case Opcode_INC:
|
|
||||||
//cout << " -- inc.";
|
|
||||||
initiateInc(current.getAddress());
|
|
||||||
break;
|
|
||||||
case Opcode_ST:
|
|
||||||
//cout << " -- store: " << current.getAddress();
|
|
||||||
initiateStore(current.getAddress());
|
|
||||||
break;
|
|
||||||
case Opcode_COMMIT:
|
|
||||||
//cout << " -- commit.";
|
|
||||||
initiateCommit();
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
WARN_EXPR(current.getOpcode());
|
|
||||||
ERROR_MSG("Invalid opcode");
|
|
||||||
};
|
|
||||||
//cout << endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
void XactAbortRequestGenerator::performCallback(NodeID proc, SubBlock& data)
|
|
||||||
{
|
|
||||||
assert(m_xact_status == XactAbortRequestGeneratorStatus_Waiting ||
|
|
||||||
m_xact_status == XactAbortRequestGeneratorStatus_Aborted);
|
|
||||||
assert(proc == m_node);
|
|
||||||
|
|
||||||
Address address = data.getAddress();
|
|
||||||
|
|
||||||
DEBUG_EXPR(TESTER_COMP, LowPrio, proc);
|
|
||||||
DEBUG_EXPR(TESTER_COMP, LowPrio, m_xact_status);
|
|
||||||
DEBUG_EXPR(TESTER_COMP, LowPrio, address);
|
|
||||||
DEBUG_EXPR(TESTER_COMP, LowPrio, data);
|
|
||||||
|
|
||||||
m_last_transition = g_eventQueue_ptr->getTime();
|
|
||||||
|
|
||||||
//cout << " " << m_node << " in performCallback, pc:" << m_pc
|
|
||||||
// << ", addr:" << address << endl;
|
|
||||||
if(m_xact_status == XactAbortRequestGeneratorStatus_Aborted){
|
|
||||||
cout << " " << m_node << " aborted, resetting pc." << endl;
|
|
||||||
m_pc = 0;
|
|
||||||
m_register = 5;
|
|
||||||
m_xact_status = XactAbortRequestGeneratorStatus_Ready;
|
|
||||||
g_eventQueue_ptr->scheduleEvent(this, waitTime());
|
|
||||||
} else {
|
|
||||||
m_xact_status = XactAbortRequestGeneratorStatus_Blocked;
|
|
||||||
|
|
||||||
bool found;
|
|
||||||
uint8 value;
|
|
||||||
switch (m_instructions[m_pc].getOpcode()){
|
|
||||||
case Opcode_BEGIN:
|
|
||||||
m_driver.recordTestLatency(g_eventQueue_ptr->getTime() - m_last_transition);
|
|
||||||
m_register = 5;
|
|
||||||
m_xact_status = XactAbortRequestGeneratorStatus_Ready;
|
|
||||||
g_eventQueue_ptr->scheduleEvent(this, waitTime());
|
|
||||||
m_pc++;
|
|
||||||
break;
|
|
||||||
case Opcode_LD:
|
|
||||||
m_driver.recordTestLatency(g_eventQueue_ptr->getTime() - m_last_transition);
|
|
||||||
m_register = data.getByte(0);
|
|
||||||
//cout << " " << m_node << " " << g_eventQueue_ptr->getTime() << " Callback--LD: " << (int) m_register << endl;
|
|
||||||
m_xact_status = XactAbortRequestGeneratorStatus_Ready;
|
|
||||||
g_eventQueue_ptr->scheduleEvent(this, waitTime());
|
|
||||||
m_pc++;
|
|
||||||
break;
|
|
||||||
//case Opcode_INC: // We shouldn't get a callback for this!
|
|
||||||
//m_driver.recordSwapLatency(g_eventQueue_ptr->getTime() - m_last_transition);
|
|
||||||
|
|
||||||
// break;
|
|
||||||
case Opcode_ST:
|
|
||||||
m_driver.recordReleaseLatency(g_eventQueue_ptr->getTime() - m_last_transition);
|
|
||||||
//data.setByte(address.getOffset(), m_register);
|
|
||||||
data.setByte(0, m_register);
|
|
||||||
//cout << " " << m_node << " " << g_eventQueue_ptr->getTime() << " Callback--ST: " << (int) m_register << endl;
|
|
||||||
|
|
||||||
//dataArray[address.getAddress()] = m_register;
|
|
||||||
found = sequencer()->setRubyMemoryValue(address, (char *) (&m_register), 1);
|
|
||||||
assert(found);
|
|
||||||
found = sequencer()->getRubyMemoryValue(address, (char *) (&value), 1);
|
|
||||||
assert(found);
|
|
||||||
assert(value == m_register);
|
|
||||||
|
|
||||||
m_xact_status = XactAbortRequestGeneratorStatus_Ready;
|
|
||||||
g_eventQueue_ptr->scheduleEvent(this, thinkTime());
|
|
||||||
m_pc++;
|
|
||||||
break;
|
|
||||||
case Opcode_COMMIT:
|
|
||||||
m_counter++;
|
|
||||||
cout << " " << m_node << " callback--commit, counter is " << m_counter << " length is: " << g_tester_length << endl;
|
|
||||||
// Check for correctness
|
|
||||||
checkCorrectness();
|
|
||||||
|
|
||||||
m_driver.recordReleaseLatency(g_eventQueue_ptr->getTime() - m_last_transition);
|
|
||||||
|
|
||||||
if (m_counter < g_tester_length) {
|
|
||||||
m_last_transition = g_eventQueue_ptr->getTime();
|
|
||||||
//pickAddress(); // Necessary?
|
|
||||||
|
|
||||||
// Create new random transaction
|
|
||||||
newTransaction();
|
|
||||||
m_pc = 0;
|
|
||||||
|
|
||||||
m_xact_status = XactAbortRequestGeneratorStatus_Ready;
|
|
||||||
g_eventQueue_ptr->scheduleEvent(this, thinkTime());
|
|
||||||
} else {
|
|
||||||
cout << "Ending" << endl;
|
|
||||||
m_driver.reportDone();
|
|
||||||
m_xact_status = XactAbortRequestGeneratorStatus_Done;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
ERROR_MSG("Invalid Opcode");
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int XactAbortRequestGenerator::thinkTime() const
|
|
||||||
{
|
|
||||||
return g_think_time;
|
|
||||||
}
|
|
||||||
|
|
||||||
int XactAbortRequestGenerator::waitTime() const
|
|
||||||
{
|
|
||||||
return g_wait_time;
|
|
||||||
}
|
|
||||||
|
|
||||||
int XactAbortRequestGenerator::holdTime() const
|
|
||||||
{
|
|
||||||
return g_hold_time;
|
|
||||||
}
|
|
||||||
|
|
||||||
void XactAbortRequestGenerator::pickAddress()
|
|
||||||
{
|
|
||||||
//m_address = m_driver.pickAddress(m_node);
|
|
||||||
}
|
|
||||||
|
|
||||||
void XactAbortRequestGenerator::initiateBeginTransaction()
|
|
||||||
{
|
|
||||||
DEBUG_MSG(TESTER_COMP, MedPrio, "### -- initiating Begin Transaction");
|
|
||||||
cout << "### -- initiating Begin " << m_node << endl;
|
|
||||||
m_xact_status = XactAbortRequestGeneratorStatus_Waiting;
|
|
||||||
sequencer()->makeRequest(CacheMsg(Address(physical_address_t(0)), Address(physical_address_t(0)), CacheRequestType_BEGIN_XACT, Address(m_pc), AccessModeType_UserMode, 1, PrefetchBit_No, 0, false, Address(0), transactionManager()->getTransactionLevel(0), 0, 0 /* only 1 SMT thread */, transactionManager()->getTimestamp(0), transactionManager()->inExposedAction(0), 0));
|
|
||||||
transactionManager()->beginTransaction();
|
|
||||||
}
|
|
||||||
|
|
||||||
void XactAbortRequestGenerator::initiateStore(Address addr)
|
|
||||||
{
|
|
||||||
//DEBUG_MSG(TESTER_COMP, MedPrio, "### -- initiating Store");
|
|
||||||
//cout << "### -- initiating Store " << m_node << endl;
|
|
||||||
m_xact_status = XactAbortRequestGeneratorStatus_Waiting;
|
|
||||||
ASSERT(transactionManager()->inTransaction(0));
|
|
||||||
sequencer()->makeRequest(CacheMsg(addr, addr, CacheRequestType_ST_XACT, Address(m_pc), AccessModeType_UserMode, 1, PrefetchBit_No, 0, false, Address(0), transactionManager()->getTransactionLevel(0), 0, 0 /* only 1 SMT thread */, transactionManager()->getTimestamp(0), transactionManager()->inExposedAction(0), 0));
|
|
||||||
}
|
|
||||||
|
|
||||||
void XactAbortRequestGenerator::initiateCommit()
|
|
||||||
{
|
|
||||||
DEBUG_MSG(TESTER_COMP, MedPrio, "### -- initiating Commit ");
|
|
||||||
cout << "### -- initiating Commit " << m_node << endl;
|
|
||||||
|
|
||||||
m_xact_status = XactAbortRequestGeneratorStatus_Waiting;
|
|
||||||
sequencer()->makeRequest(CacheMsg(Address(physical_address_t(0)), Address(physical_address_t(0)), CacheRequestType_COMMIT_XACT, Address(m_pc), AccessModeType_UserMode, 1, PrefetchBit_No, 0, false, Address(0), transactionManager()->getTransactionLevel(0), 0, 0 /* only 1 SMT thread */, transactionManager()->getTimestamp(0), transactionManager()->inExposedAction(0), 0));
|
|
||||||
transactionManager()->commitTransaction();
|
|
||||||
}
|
|
||||||
|
|
||||||
void XactAbortRequestGenerator::initiateLoad(Address addr)
|
|
||||||
{
|
|
||||||
//DEBUG_MSG(TESTER_COMP, MedPrio, "### -- initiating Load ");
|
|
||||||
//cout << "### -- initiating Load " << m_node << endl;
|
|
||||||
m_xact_status = XactAbortRequestGeneratorStatus_Waiting;
|
|
||||||
ASSERT(transactionManager()->inTransaction(0));
|
|
||||||
sequencer()->makeRequest(CacheMsg(addr, addr, CacheRequestType_LD_XACT, Address(m_pc), AccessModeType_UserMode, 1, PrefetchBit_No, 0, false, Address(0), transactionManager()->getTransactionLevel(0), 0, 0 /* only 1 SMT thread */, transactionManager()->getTimestamp(0), transactionManager()->inExposedAction(0), 0));
|
|
||||||
}
|
|
||||||
|
|
||||||
void XactAbortRequestGenerator::initiateInc(Address addr)
|
|
||||||
{
|
|
||||||
//DEBUG_MSG(TESTER_COMP, MedPrio, "### -- initiating Load ");
|
|
||||||
//cout << "### -- initiating Inc " << m_node << endl;
|
|
||||||
m_register++;
|
|
||||||
m_xact_status = XactAbortRequestGeneratorStatus_Ready;
|
|
||||||
g_eventQueue_ptr->scheduleEvent(this, holdTime());
|
|
||||||
m_pc++;
|
|
||||||
}
|
|
||||||
|
|
||||||
void XactAbortRequestGenerator::checkCorrectness(){
|
|
||||||
// Execute the transaction on the test array
|
|
||||||
int testPC = 0;
|
|
||||||
bool done = false;
|
|
||||||
for(int i=0; i<XACT_LENGTH && !done; ++i){
|
|
||||||
Opcode op = m_instructions[i].getOpcode();
|
|
||||||
Address addr = m_instructions[i].getAddress();
|
|
||||||
ASSERT(addr.getAddress() < testArray.size());
|
|
||||||
uint8 reg_val;
|
|
||||||
switch(op){
|
|
||||||
case Opcode_BEGIN:
|
|
||||||
reg_val = 0;
|
|
||||||
break; // do nothing
|
|
||||||
case Opcode_LD:
|
|
||||||
reg_val = testArray[addr.getAddress()];
|
|
||||||
//cout << m_node << " LD: " << addr << ", " << (int) reg_val << endl;
|
|
||||||
break;
|
|
||||||
case Opcode_INC:
|
|
||||||
reg_val++;
|
|
||||||
//cout << m_node << " INC: " << (int) reg_val << endl;
|
|
||||||
break;
|
|
||||||
case Opcode_ST:
|
|
||||||
testArray[addr.getAddress()] = reg_val;
|
|
||||||
//cout << m_node << " ST: " << addr << ", " << (int) reg_val << endl;
|
|
||||||
break;
|
|
||||||
case Opcode_COMMIT:
|
|
||||||
done = true;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
ERROR_MSG("Invalid Opcode.");
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
bool success = true;
|
|
||||||
uint8 ruby_value;
|
|
||||||
bool found = false;
|
|
||||||
for(int i=0; i<XACT_LENGTH && !done; ++i){
|
|
||||||
Opcode op = m_instructions[i].getOpcode();
|
|
||||||
Address addr = m_instructions[i].getAddress();
|
|
||||||
|
|
||||||
uint8 reg_val;
|
|
||||||
switch(op){
|
|
||||||
case Opcode_BEGIN:
|
|
||||||
case Opcode_INC:
|
|
||||||
break; // do nothing
|
|
||||||
case Opcode_LD:
|
|
||||||
case Opcode_ST:
|
|
||||||
found = sequencer()->getRubyMemoryValue(m_instructions[i].getAddress(), (char *) &ruby_value, 1);
|
|
||||||
assert(found);
|
|
||||||
|
|
||||||
if (ruby_value != testArray[i]){
|
|
||||||
success = false;
|
|
||||||
WARN_MSG("DATA MISMATCH!");
|
|
||||||
WARN_EXPR((int) ruby_value);
|
|
||||||
WARN_EXPR((int) testArray[i]);
|
|
||||||
WARN_EXPR(i);
|
|
||||||
assert(success);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case Opcode_COMMIT:
|
|
||||||
done = true;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
ERROR_MSG("Invalid Opcode.");
|
|
||||||
};
|
|
||||||
}
|
|
||||||
cout << m_node << " CORRECT!" << endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
Sequencer* XactAbortRequestGenerator::sequencer() const
|
|
||||||
{
|
|
||||||
return g_system_ptr->getChip(m_node/RubyConfig::numberOfProcsPerChip())->getSequencer(m_node%RubyConfig::numberOfProcsPerChip());
|
|
||||||
}
|
|
||||||
|
|
||||||
TransactionManager* XactAbortRequestGenerator::transactionManager() const
|
|
||||||
{
|
|
||||||
return g_system_ptr->getChip(m_node/RubyConfig::numberOfProcsPerChip())->getTransactionManager(m_node%RubyConfig::numberOfProcsPerChip());
|
|
||||||
}
|
|
||||||
|
|
||||||
void XactAbortRequestGenerator::print(ostream& out) const
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void XactAbortRequestGenerator::abortTransaction(){
|
|
||||||
cout << " " << m_node << " *** ABORT! ***" << endl;
|
|
||||||
//m_pc = 0;
|
|
||||||
//m_register = 5;
|
|
||||||
m_xact_status = XactAbortRequestGeneratorStatus_Aborted;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif //XACT_MEM
|
|
|
@ -1,122 +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$
|
|
||||||
*
|
|
||||||
* Description:
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef XACTABORTREQUESTGENERATOR_H
|
|
||||||
#define XACTABORTREQUESTGENERATOR_H
|
|
||||||
|
|
||||||
#ifdef XACT_MEM
|
|
||||||
|
|
||||||
#include "mem/ruby/tester/RequestGenerator.hh"
|
|
||||||
#include "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;
|
|
||||||
class Instruction;
|
|
||||||
class TransactionManager;
|
|
||||||
|
|
||||||
#define MAX_ADDRESS 16777216
|
|
||||||
|
|
||||||
enum XactAbortRequestGeneratorStatus {
|
|
||||||
XactAbortRequestGeneratorStatus_Waiting,
|
|
||||||
XactAbortRequestGeneratorStatus_Ready,
|
|
||||||
XactAbortRequestGeneratorStatus_Blocked,
|
|
||||||
XactAbortRequestGeneratorStatus_Aborted,
|
|
||||||
XactAbortRequestGeneratorStatus_Done
|
|
||||||
};
|
|
||||||
|
|
||||||
class XactAbortRequestGenerator : public RequestGenerator {
|
|
||||||
public:
|
|
||||||
// Constructors
|
|
||||||
XactAbortRequestGenerator(NodeID node, SyntheticDriver& driver);
|
|
||||||
|
|
||||||
// Destructor
|
|
||||||
~XactAbortRequestGenerator();
|
|
||||||
|
|
||||||
// Public Methods
|
|
||||||
void wakeup();
|
|
||||||
void performCallback(NodeID proc, SubBlock& data);
|
|
||||||
void abortTransaction();
|
|
||||||
|
|
||||||
void print(ostream& out) const;
|
|
||||||
private:
|
|
||||||
// Private Methods
|
|
||||||
int thinkTime() const;
|
|
||||||
int waitTime() const;
|
|
||||||
int holdTime() const;
|
|
||||||
void initiateBeginTransaction();
|
|
||||||
void initiateStore(Address a);
|
|
||||||
void initiateCommit();
|
|
||||||
void initiateInc(Address a);
|
|
||||||
void initiateLoad(Address a);
|
|
||||||
void pickAddress();
|
|
||||||
Sequencer* sequencer() const;
|
|
||||||
TransactionManager* transactionManager() const;
|
|
||||||
void execute();
|
|
||||||
|
|
||||||
void checkCorrectness();
|
|
||||||
|
|
||||||
// Private copy constructor and assignment operator
|
|
||||||
XactAbortRequestGenerator(const XactAbortRequestGenerator& obj);
|
|
||||||
XactAbortRequestGenerator& operator=(const XactAbortRequestGenerator& obj);
|
|
||||||
|
|
||||||
void newTransaction();
|
|
||||||
|
|
||||||
// Data Members (m_ prefix)
|
|
||||||
SyntheticDriver& m_driver;
|
|
||||||
NodeID m_node;
|
|
||||||
XactAbortRequestGeneratorStatus m_xact_status;
|
|
||||||
int m_counter;
|
|
||||||
Time m_last_transition;
|
|
||||||
Address m_address;
|
|
||||||
|
|
||||||
Instruction *m_instructions;
|
|
||||||
int m_pc;
|
|
||||||
uint8 m_register;
|
|
||||||
static Vector<uint8> testArray;
|
|
||||||
//static uint8 dataArray[];
|
|
||||||
};
|
|
||||||
|
|
||||||
// Output operator declaration
|
|
||||||
ostream& operator<<(ostream& out, const XactAbortRequestGenerator& obj);
|
|
||||||
|
|
||||||
// ******************* Definitions *******************
|
|
||||||
|
|
||||||
// Output operator definition
|
|
||||||
extern inline
|
|
||||||
ostream& operator<<(ostream& out, const XactAbortRequestGenerator& obj)
|
|
||||||
{
|
|
||||||
obj.print(out);
|
|
||||||
out << flush;
|
|
||||||
return out;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif //XACT_MEM
|
|
||||||
|
|
||||||
#endif //REQUESTGENERATOR_H
|
|
||||||
|
|
|
@ -1,637 +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: XactRequestGenerator.C 1.7 05/09/22 16:49:19-05:00 xu@s0-29.cs.wisc.edu $
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "mem/ruby/tester/XactRequestGenerator.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"
|
|
||||||
#include "mem/ruby/tester/Instruction.hh"
|
|
||||||
|
|
||||||
XactRequestGenerator::XactRequestGenerator(NodeID node, SyntheticDriver& driver) :
|
|
||||||
m_driver(driver), RequestGenerator(node, driver)
|
|
||||||
{
|
|
||||||
DEBUG_EXPR(TESTER_COMP, MedPrio, "#### -- Creating XactRequestGenerator\n");
|
|
||||||
cout << "#### -- Creating XactRequestGenerator " << node << endl;
|
|
||||||
|
|
||||||
assert(XACT_SIZE > 0);
|
|
||||||
testArray = new uint8[g_MEMORY_SIZE_BYTES];;
|
|
||||||
// Create instructions
|
|
||||||
m_instructions = new Instruction[XACT_LENGTH];
|
|
||||||
newTransaction(true);
|
|
||||||
|
|
||||||
m_status = XactRequestGeneratorStatus_Ready;
|
|
||||||
m_last_transition = 0;
|
|
||||||
m_node = node;
|
|
||||||
//pickAddress();
|
|
||||||
m_counter = 0;
|
|
||||||
m_register = 5;
|
|
||||||
m_pc = 0;
|
|
||||||
|
|
||||||
m_abortPending = false;
|
|
||||||
g_eventQueue_ptr->scheduleEvent(this, 1+(random() % 200));
|
|
||||||
}
|
|
||||||
|
|
||||||
void XactRequestGenerator::newTransaction(bool init){
|
|
||||||
// important: reset abort flag
|
|
||||||
m_abortPending = false;
|
|
||||||
|
|
||||||
int depth = 0;
|
|
||||||
bool prev_ldst = false;
|
|
||||||
m_size = (random() % (XACT_LENGTH-2)) + 2;
|
|
||||||
cout << "XactRequestGenerator::newTransaction m_size=" << m_size << endl;
|
|
||||||
ASSERT(m_size >= 2);
|
|
||||||
if (!init)
|
|
||||||
ASSERT(!transactionManager()->inTransaction(0));
|
|
||||||
m_transaction = (random() % 2);
|
|
||||||
|
|
||||||
if(m_transaction){
|
|
||||||
cout << " " << m_node << " new transaction " << endl;
|
|
||||||
} else {
|
|
||||||
cout << " " << m_node << " new NON-transaction " << endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
cout << "***INSTR STREAM ";
|
|
||||||
for(int i=0; i<m_size; ++i){
|
|
||||||
if (i == 0 && m_transaction){ // new xact must start with begin
|
|
||||||
m_instructions[i].init(Opcode_BEGIN, Address(1));
|
|
||||||
depth++;
|
|
||||||
cout << "begin ";
|
|
||||||
prev_ldst = false;
|
|
||||||
} else if (i == m_size - 1){
|
|
||||||
if(m_transaction) { // new xact must end with commit
|
|
||||||
m_instructions[i].init(Opcode_COMMIT, Address(1));
|
|
||||||
depth--;
|
|
||||||
cout << "commit ";
|
|
||||||
} else {
|
|
||||||
m_instructions[i].init(Opcode_DONE, Address(1));
|
|
||||||
cout << "done ";
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
int selectAction;
|
|
||||||
if (!m_transaction) { // non-xact: must choose op
|
|
||||||
selectAction = 1;
|
|
||||||
} else { // xact
|
|
||||||
if (depth == m_size - i) { // must choose commit
|
|
||||||
selectAction = 0;
|
|
||||||
} else if (prev_ldst) { // only choose xact if intervenient ld/st
|
|
||||||
if (m_size - i < depth + 3) { // can choose op or
|
|
||||||
// commit (can't choose
|
|
||||||
// begin)
|
|
||||||
selectAction = (random() % 2);
|
|
||||||
} else if (depth == 0) { // can choose begin or op (can't
|
|
||||||
// choose commit)
|
|
||||||
selectAction = (random() % 2);
|
|
||||||
if (selectAction == 0) selectAction = 2;
|
|
||||||
} else { // can choose begin, op, or commit
|
|
||||||
selectAction = (random() % 3);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
selectAction = 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
physical_address_t address;
|
|
||||||
int selectOpcode;
|
|
||||||
switch (selectAction) {
|
|
||||||
case 0: // commit
|
|
||||||
m_instructions[i].init(Opcode_COMMIT, Address(1));
|
|
||||||
depth--;
|
|
||||||
cout << "commit ";
|
|
||||||
prev_ldst = false;
|
|
||||||
break;
|
|
||||||
case 1:
|
|
||||||
address = (random() % XACT_SIZE);
|
|
||||||
//cout << "address: " << address << endl;
|
|
||||||
//cout << "XACT_SIZE: " << XACT_SIZE << endl;
|
|
||||||
|
|
||||||
//assert(address < XACT_SIZE);
|
|
||||||
//physical_address_t address = 0;
|
|
||||||
selectOpcode = random() % 3;
|
|
||||||
Opcode op;
|
|
||||||
switch(selectOpcode){
|
|
||||||
case 0:
|
|
||||||
op = Opcode_LD;
|
|
||||||
cout << "ld ";
|
|
||||||
break;
|
|
||||||
case 1:
|
|
||||||
op = Opcode_ST;
|
|
||||||
cout << "st ";
|
|
||||||
break;
|
|
||||||
case 2:
|
|
||||||
op = Opcode_INC;
|
|
||||||
cout << "inc ";
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
assert(false);
|
|
||||||
};
|
|
||||||
assert(op < Opcode_NUM_OPCODES);
|
|
||||||
m_instructions[i].init(op, Address(address));
|
|
||||||
prev_ldst = true;
|
|
||||||
break;
|
|
||||||
case 2:
|
|
||||||
m_instructions[i].init(Opcode_BEGIN, Address(1));
|
|
||||||
depth++;
|
|
||||||
cout << "begin ";
|
|
||||||
prev_ldst = false;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
assert(false);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
cout << endl;
|
|
||||||
if(m_transaction){
|
|
||||||
ASSERT(m_instructions[0].getOpcode() == Opcode_BEGIN);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
XactRequestGenerator::~XactRequestGenerator()
|
|
||||||
{
|
|
||||||
if(testArray){
|
|
||||||
delete [] testArray;
|
|
||||||
testArray = NULL;
|
|
||||||
}
|
|
||||||
delete m_instructions;
|
|
||||||
}
|
|
||||||
|
|
||||||
void XactRequestGenerator::wakeup()
|
|
||||||
{
|
|
||||||
DEBUG_EXPR(TESTER_COMP, MedPrio, m_node);
|
|
||||||
DEBUG_EXPR(TESTER_COMP, MedPrio, m_status);
|
|
||||||
|
|
||||||
assert(m_status == XactRequestGeneratorStatus_Ready || m_status == XactRequestGeneratorStatus_Aborted);
|
|
||||||
m_status = XactRequestGeneratorStatus_Blocked;
|
|
||||||
|
|
||||||
m_last_transition = g_eventQueue_ptr->getTime();
|
|
||||||
execute();
|
|
||||||
}
|
|
||||||
|
|
||||||
void XactRequestGenerator::execute(){
|
|
||||||
cout << "XactRequestGenerator::execute m_node=" << m_node << " m_pc=" << m_pc << " m_size=" << m_size << endl;
|
|
||||||
assert(m_pc >= 0);
|
|
||||||
assert(m_pc < m_size);
|
|
||||||
assert(m_pc < XACT_LENGTH);
|
|
||||||
|
|
||||||
Instruction current = m_instructions[m_pc];
|
|
||||||
switch (current.getOpcode()){
|
|
||||||
case Opcode_BEGIN:
|
|
||||||
cout << " -- begin.";
|
|
||||||
initiateBeginTransaction();
|
|
||||||
break;
|
|
||||||
case Opcode_LD:
|
|
||||||
cout << " -- load: " << current.getAddress();
|
|
||||||
initiateLoad(current.getAddress());
|
|
||||||
break;
|
|
||||||
case Opcode_INC:
|
|
||||||
cout << " -- inc.";
|
|
||||||
initiateInc(current.getAddress());
|
|
||||||
break;
|
|
||||||
case Opcode_ST:
|
|
||||||
cout << " -- store: " << current.getAddress();
|
|
||||||
initiateStore(current.getAddress());
|
|
||||||
break;
|
|
||||||
case Opcode_COMMIT:
|
|
||||||
cout << " -- commit.";
|
|
||||||
initiateCommit();
|
|
||||||
break;
|
|
||||||
case Opcode_DONE:
|
|
||||||
cout << " -- done.";
|
|
||||||
initiateDone();
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
WARN_EXPR(current.getOpcode());
|
|
||||||
ERROR_MSG("Invalid opcode");
|
|
||||||
};
|
|
||||||
cout << endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
void XactRequestGenerator::performCallback(NodeID proc, SubBlock& data)
|
|
||||||
{
|
|
||||||
cout << "XactRequestGenerator::performCallback m_node=" << m_node << endl;
|
|
||||||
assert(m_status == XactRequestGeneratorStatus_Waiting ||
|
|
||||||
m_status == XactRequestGeneratorStatus_Aborted);
|
|
||||||
assert(proc == m_node);
|
|
||||||
|
|
||||||
Address address = data.getAddress();
|
|
||||||
//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);
|
|
||||||
|
|
||||||
m_last_transition = g_eventQueue_ptr->getTime();
|
|
||||||
|
|
||||||
cout << " " << m_node << " in performCallback, pc:" << m_pc
|
|
||||||
<< ", addr:" << address << endl;
|
|
||||||
|
|
||||||
|
|
||||||
int depth;
|
|
||||||
if(m_status == XactRequestGeneratorStatus_Aborted){
|
|
||||||
depth = transactionManager()->postAbortIndex(0);
|
|
||||||
m_pc = pc_stack[depth];
|
|
||||||
cout << "XactRequestGenerator::performCallback m_node=" << m_node << " setting m_pc=" << m_pc << endl;
|
|
||||||
printPcStack(depth);
|
|
||||||
m_register = 5;
|
|
||||||
m_status = XactRequestGeneratorStatus_Ready;
|
|
||||||
g_eventQueue_ptr->scheduleEvent(this, ABORT_RETRY_TIME);
|
|
||||||
} else {
|
|
||||||
m_status = XactRequestGeneratorStatus_Blocked;
|
|
||||||
bool found, outermost;
|
|
||||||
uint8 value;
|
|
||||||
switch (m_instructions[m_pc].getOpcode()){
|
|
||||||
case Opcode_BEGIN:
|
|
||||||
m_driver.recordTestLatency(g_eventQueue_ptr->getTime() - m_last_transition);
|
|
||||||
m_register = 5;
|
|
||||||
m_status = XactRequestGeneratorStatus_Ready;
|
|
||||||
g_eventQueue_ptr->scheduleEvent(this, waitTime());
|
|
||||||
depth = transactionManager()->getDepth(0);
|
|
||||||
if (!transactionManager()->isSubsuming(0)) {
|
|
||||||
pc_stack[depth - 1] = m_pc;
|
|
||||||
cout << "XactRequestGenerator::performCallback m_node=" << m_node << " SETTING PC_STACK" << endl;
|
|
||||||
printPcStack(depth);
|
|
||||||
}
|
|
||||||
m_pc++;
|
|
||||||
break;
|
|
||||||
case Opcode_LD:
|
|
||||||
m_driver.recordTestLatency(g_eventQueue_ptr->getTime() - m_last_transition);
|
|
||||||
m_register = data.getByte(0);
|
|
||||||
//cout << " " << m_node << " " << g_eventQueue_ptr->getTime() << " Callback--LD: " << (int) m_register << endl;
|
|
||||||
m_status = XactRequestGeneratorStatus_Ready;
|
|
||||||
g_eventQueue_ptr->scheduleEvent(this, waitTime());
|
|
||||||
m_pc++;
|
|
||||||
break;
|
|
||||||
//case Opcode_INC: // We shouldn't get a callback for this!
|
|
||||||
//m_driver.recordSwapLatency(g_eventQueue_ptr->getTime() - m_last_transition);
|
|
||||||
|
|
||||||
// break;
|
|
||||||
case Opcode_ST:
|
|
||||||
m_driver.recordReleaseLatency(g_eventQueue_ptr->getTime() - m_last_transition);
|
|
||||||
//data.setByte(address.getOffset(), m_register);
|
|
||||||
data.setByte(0, m_register);
|
|
||||||
//cout << " " << m_node << " " << g_eventQueue_ptr->getTime() << " Callback--ST: " << (int) m_register << endl;
|
|
||||||
|
|
||||||
//dataArray[address.getAddress()] = m_register;
|
|
||||||
found = sequencer()->setRubyMemoryValue(address, (char *) (&m_register), 1);
|
|
||||||
assert(found);
|
|
||||||
found = sequencer()->getRubyMemoryValue(address, (char *) (&value), 1);
|
|
||||||
assert(found);
|
|
||||||
assert(value == m_register);
|
|
||||||
|
|
||||||
m_status = XactRequestGeneratorStatus_Ready;
|
|
||||||
g_eventQueue_ptr->scheduleEvent(this, thinkTime());
|
|
||||||
m_pc++;
|
|
||||||
break;
|
|
||||||
case Opcode_COMMIT:
|
|
||||||
outermost = transactionManager()->getDepth(0) == 1;
|
|
||||||
if (outermost) { // about to commit outermost
|
|
||||||
m_counter++;
|
|
||||||
}
|
|
||||||
|
|
||||||
cout << " " << m_node << " callback--commit, counter is " << m_counter << " length is: " << g_tester_length << endl;
|
|
||||||
// Check for correctness
|
|
||||||
|
|
||||||
checkCorrectness();
|
|
||||||
transactionManager()->commitTransaction();
|
|
||||||
|
|
||||||
m_driver.recordReleaseLatency(g_eventQueue_ptr->getTime() - m_last_transition);
|
|
||||||
|
|
||||||
if (outermost) {
|
|
||||||
if (m_counter < g_tester_length) {
|
|
||||||
m_last_transition = g_eventQueue_ptr->getTime();
|
|
||||||
//pickAddress(); // Necessary?
|
|
||||||
|
|
||||||
// Create new random transaction
|
|
||||||
cout << "CREATING NEW RANDOM XACT SET" << endl;
|
|
||||||
newTransaction(false);
|
|
||||||
m_pc = 0;
|
|
||||||
|
|
||||||
m_status = XactRequestGeneratorStatus_Ready;
|
|
||||||
g_eventQueue_ptr->scheduleEvent(this, thinkTime());
|
|
||||||
} else {
|
|
||||||
cout << " " << m_node << " Done." << endl;
|
|
||||||
m_driver.reportDone();
|
|
||||||
m_status = XactRequestGeneratorStatus_Done;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
m_status = XactRequestGeneratorStatus_Ready;
|
|
||||||
g_eventQueue_ptr->scheduleEvent(this, thinkTime());
|
|
||||||
m_pc++;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
ERROR_MSG("Invalid Opcode");
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int XactRequestGenerator::thinkTime() const
|
|
||||||
{
|
|
||||||
return g_think_time;
|
|
||||||
}
|
|
||||||
|
|
||||||
int XactRequestGenerator::waitTime() const
|
|
||||||
{
|
|
||||||
return g_wait_time;
|
|
||||||
}
|
|
||||||
|
|
||||||
int XactRequestGenerator::holdTime() const
|
|
||||||
{
|
|
||||||
return g_hold_time;
|
|
||||||
}
|
|
||||||
|
|
||||||
void XactRequestGenerator::pickAddress()
|
|
||||||
{
|
|
||||||
//m_address = m_driver.pickAddress(m_node);
|
|
||||||
}
|
|
||||||
|
|
||||||
void XactRequestGenerator::initiateBeginTransaction()
|
|
||||||
{
|
|
||||||
DEBUG_MSG(TESTER_COMP, MedPrio, "### -- initiating Begin Transaction");
|
|
||||||
cout << "### -- initiating Begin " << m_node << endl;
|
|
||||||
m_status = XactRequestGeneratorStatus_Waiting;
|
|
||||||
sequencer()->makeRequest(CacheMsg(Address(physical_address_t(0)), Address(physical_address_t(0)), CacheRequestType_BEGIN_XACT, Address(m_pc), AccessModeType_UserMode, 1, PrefetchBit_No, 0, false, Address(0), transactionManager()->getTransactionLevel(0), 0, 0 /* only 1 SMT thread */, transactionManager()->getTimestamp(0), transactionManager()->inExposedAction(0), 0));
|
|
||||||
transactionManager()->beginTransaction();
|
|
||||||
}
|
|
||||||
|
|
||||||
void XactRequestGenerator::initiateStore(Address addr)
|
|
||||||
{
|
|
||||||
DEBUG_MSG(TESTER_COMP, MedPrio, "### -- initiating Store");
|
|
||||||
DEBUG_MSG(TESTER_COMP, MedPrio, addr);
|
|
||||||
cout << "### -- initiating Store " << m_node << endl;
|
|
||||||
m_status = XactRequestGeneratorStatus_Waiting;
|
|
||||||
if(m_transaction){
|
|
||||||
sequencer()->makeRequest(CacheMsg(addr, addr, CacheRequestType_ST_XACT, Address(m_pc), AccessModeType_UserMode, 1, PrefetchBit_No, 0, false, Address(0), transactionManager()->getTransactionLevel(0), 0, 0 /* only 1 SMT thread */, transactionManager()->getTimestamp(0), transactionManager()->inExposedAction(0), 0));
|
|
||||||
} else {
|
|
||||||
sequencer()->makeRequest(CacheMsg(addr, addr, CacheRequestType_ST, Address(m_pc), AccessModeType_UserMode, 1, PrefetchBit_No, 0, false, Address(0), transactionManager()->getTransactionLevel(0), 0, 0 /* only 1 SMT thread */, transactionManager()->getTimestamp(0),transactionManager()->inExposedAction(0), 0));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void XactRequestGenerator::initiateCommit()
|
|
||||||
{
|
|
||||||
DEBUG_MSG(TESTER_COMP, MedPrio, "### -- initiating Commit ");
|
|
||||||
cout << "### -- initiating Commit " << m_node << endl;
|
|
||||||
|
|
||||||
m_status = XactRequestGeneratorStatus_Waiting;
|
|
||||||
sequencer()->makeRequest(CacheMsg(Address(physical_address_t(0)), Address(physical_address_t(0)), CacheRequestType_COMMIT_XACT, Address(m_pc), AccessModeType_UserMode, 1, PrefetchBit_No, 0, false, Address(0), transactionManager()->getTransactionLevel(0), 0, 0 /* only 1 SMT thread */, transactionManager()->getTimestamp(0), transactionManager()->inExposedAction(0), 0));
|
|
||||||
}
|
|
||||||
|
|
||||||
void XactRequestGenerator::initiateLoad(Address addr)
|
|
||||||
{
|
|
||||||
DEBUG_MSG(TESTER_COMP, MedPrio, "### -- initiating Load ");
|
|
||||||
DEBUG_MSG(TESTER_COMP, MedPrio, addr);
|
|
||||||
|
|
||||||
m_status = XactRequestGeneratorStatus_Waiting;
|
|
||||||
if(m_transaction){
|
|
||||||
cout << "### -- initiating Load XACT" << m_node << endl;
|
|
||||||
sequencer()->makeRequest(CacheMsg(addr, addr, CacheRequestType_LD_XACT, Address(m_pc), AccessModeType_UserMode, 1, PrefetchBit_No, 0, false, Address(0), transactionManager()->getTransactionLevel(0), 0, 0 /* only 1 SMT thread */, transactionManager()->getTimestamp(0), transactionManager()->inExposedAction(0), 0 ));
|
|
||||||
} else {
|
|
||||||
cout << "### -- initiating Load " << m_node << endl;
|
|
||||||
sequencer()->makeRequest(CacheMsg(addr, addr, CacheRequestType_LD, Address(m_pc), AccessModeType_UserMode, 1, PrefetchBit_No, 0, false, Address(0), transactionManager()->getTransactionLevel(0), 0, 0 /* only 1 SMT thread */, transactionManager()->getTimestamp(0), transactionManager()->inExposedAction(0), 0));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void XactRequestGenerator::initiateInc(Address addr)
|
|
||||||
{
|
|
||||||
DEBUG_MSG(TESTER_COMP, MedPrio, "### -- initiating Inc ");
|
|
||||||
DEBUG_MSG(TESTER_COMP, MedPrio, addr);
|
|
||||||
cout << "### -- initiating Inc " << m_node << endl;
|
|
||||||
m_register++;
|
|
||||||
m_status = XactRequestGeneratorStatus_Ready;
|
|
||||||
g_eventQueue_ptr->scheduleEvent(this, holdTime());
|
|
||||||
m_pc++;
|
|
||||||
}
|
|
||||||
|
|
||||||
void XactRequestGenerator::initiateDone()
|
|
||||||
{
|
|
||||||
DEBUG_MSG(TESTER_COMP, MedPrio, "### -- initiating Done ");
|
|
||||||
cout << "### -- initiating Done " << m_node << endl;
|
|
||||||
newTransaction(false);
|
|
||||||
m_pc = 0;
|
|
||||||
//m_register = 5;
|
|
||||||
|
|
||||||
m_status = XactRequestGeneratorStatus_Ready;
|
|
||||||
g_eventQueue_ptr->scheduleEvent(this, thinkTime());
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
void XactRequestGenerator::checkCorrectness(){
|
|
||||||
// Execute the transaction on the test array
|
|
||||||
int testPC = 0;
|
|
||||||
bool done = false;
|
|
||||||
for(int i=0; i<XACT_LENGTH && !done; ++i){
|
|
||||||
Opcode op = m_instructions[i].getOpcode();
|
|
||||||
Address addr = m_instructions[i].getAddress();
|
|
||||||
|
|
||||||
uint8 reg_val;
|
|
||||||
switch(op){
|
|
||||||
case Opcode_BEGIN:
|
|
||||||
reg_val = 0;
|
|
||||||
break; // do nothing
|
|
||||||
case Opcode_LD:
|
|
||||||
//cout << "\tcheckCorrectness " << m_node << " LD: " << addr << " address = " << hex << addr.getAddress() << endl;
|
|
||||||
ASSERT(addr.getAddress() < g_MEMORY_SIZE_BYTES);
|
|
||||||
reg_val = testArray[addr.getAddress()];
|
|
||||||
//cout << m_node << " LD: " << addr << ", " << (int) reg_val << endl;
|
|
||||||
break;
|
|
||||||
case Opcode_INC:
|
|
||||||
reg_val++;
|
|
||||||
//cout << m_node << " INC: " << (int) reg_val << endl;
|
|
||||||
break;
|
|
||||||
case Opcode_ST:
|
|
||||||
//cout << "\tcheckCorrectness " << m_node << " ST: " << addr << " address = " << hex << addr.getAddress() << endl;
|
|
||||||
ASSERT(addr.getAddress() < g_MEMORY_SIZE_BYTES);
|
|
||||||
testArray[addr.getAddress()] = reg_val;
|
|
||||||
//cout << m_node << " ST: " << addr << ", " << (int) reg_val << endl;
|
|
||||||
break;
|
|
||||||
case Opcode_DONE:
|
|
||||||
case Opcode_COMMIT:
|
|
||||||
done = true;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
ERROR_MSG("Invalid Opcode.");
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
bool success = true;
|
|
||||||
uint8 ruby_value;
|
|
||||||
done = false;
|
|
||||||
bool found = false;
|
|
||||||
for(int i=0; i<XACT_LENGTH && !done; ++i){
|
|
||||||
Opcode op = m_instructions[i].getOpcode();
|
|
||||||
Address addr = m_instructions[i].getAddress();
|
|
||||||
|
|
||||||
uint8 reg_val;
|
|
||||||
switch(op){
|
|
||||||
case Opcode_BEGIN:
|
|
||||||
case Opcode_INC:
|
|
||||||
break; // do nothing
|
|
||||||
case Opcode_LD:
|
|
||||||
case Opcode_ST:
|
|
||||||
found = sequencer()->getRubyMemoryValue(m_instructions[i].getAddress(), (char *) &ruby_value, 1);
|
|
||||||
assert(found);
|
|
||||||
|
|
||||||
if (ruby_value != testArray[i]){
|
|
||||||
success = false;
|
|
||||||
WARN_MSG("DATA MISMATCH!");
|
|
||||||
WARN_EXPR((int) ruby_value);
|
|
||||||
WARN_EXPR((int) testArray[i]);
|
|
||||||
WARN_EXPR(i);
|
|
||||||
assert(success);
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
case Opcode_COMMIT:
|
|
||||||
done = true;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
ERROR_MSG("Invalid Opcode.");
|
|
||||||
};
|
|
||||||
}
|
|
||||||
cout << m_node << " CORRECT!" << endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
Sequencer* XactRequestGenerator::sequencer() const
|
|
||||||
{
|
|
||||||
return g_system_ptr->getChip(m_node/RubyConfig::numberOfProcsPerChip())->getSequencer(m_node%RubyConfig::numberOfProcsPerChip());
|
|
||||||
}
|
|
||||||
|
|
||||||
TransactionManager* XactRequestGenerator::transactionManager() const
|
|
||||||
{
|
|
||||||
return g_system_ptr->getChip(m_node/RubyConfig::numberOfProcsPerChip())->getTransactionManager(m_node%RubyConfig::numberOfProcsPerChip());
|
|
||||||
}
|
|
||||||
|
|
||||||
void XactRequestGenerator::print(ostream& out) const
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void XactRequestGenerator::abortTransaction(){
|
|
||||||
cout << " " << m_node << " *** ABORT! ***" << endl;
|
|
||||||
m_status = XactRequestGeneratorStatus_Aborted;
|
|
||||||
}
|
|
||||||
|
|
||||||
void XactRequestGenerator::printPcStack(int depth) {
|
|
||||||
cout << "XactRequestGenerator::printPcStack m_node=" << m_node << " [";
|
|
||||||
for (int i = 0; i < depth; i++) {
|
|
||||||
cout << pc_stack[i] << ", ";
|
|
||||||
}
|
|
||||||
cout << "]" << endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
void XactRequestGenerator::notifySendNack( const Address & physicalAddr, uint64 remote_timestamp, const MachineID & remote_id) {
|
|
||||||
Address addr = physicalAddr;
|
|
||||||
addr.makeLineAddress();
|
|
||||||
TransactionManager * xact_mgr = transactionManager();
|
|
||||||
bool isOlder = xact_mgr->isOlder(remote_timestamp, remote_id, addr );
|
|
||||||
if(isOlder){
|
|
||||||
bool inReadSet = xact_mgr->isInReadSetFilter(physicalAddr, 0);
|
|
||||||
bool inWriteSet = xact_mgr->isInWriteSetFilter(physicalAddr, 0);
|
|
||||||
// addr should be in perfect or Bloom filter
|
|
||||||
ASSERT( inReadSet || inWriteSet );
|
|
||||||
cout << "notifySendNack addr = " << addr << " setting POSSIBLE CYCLE " << " my_ts = " << xact_mgr->getTimestamp(0) << " remote_ts = " << remote_timestamp << " proc = " << m_node << endl;
|
|
||||||
xact_mgr->setPossibleCycle(addr, L1CacheMachIDToProcessorNum(remote_id), 0 /*remote thread*/ , remote_timestamp, 0 /*our thread*/);
|
|
||||||
}
|
|
||||||
// otherwise don't set the proc possible cycle flag
|
|
||||||
}
|
|
||||||
|
|
||||||
void XactRequestGenerator::notifyReceiveNack( const Address & physicalAddr, uint64 remote_timestamp, const MachineID & remote_id ) {
|
|
||||||
Address addr = physicalAddr;
|
|
||||||
addr.makeLineAddress();
|
|
||||||
// check whether the possible cycle is set, and whether remote_timestamp is older.
|
|
||||||
// we only have 1 SMT thread
|
|
||||||
TransactionManager * xact_mgr = transactionManager();
|
|
||||||
int local_timestamp = xact_mgr->getTimestamp(0);
|
|
||||||
bool possible_cycle = xact_mgr->possibleCycle(0);
|
|
||||||
// calculate isOlder() only if possible_cycle is set. This is because isOlder assumes proc is in a transaction
|
|
||||||
bool isOlder = false;
|
|
||||||
if(possible_cycle){
|
|
||||||
isOlder = xact_mgr->isOlder(remote_timestamp, remote_id, addr );
|
|
||||||
}
|
|
||||||
|
|
||||||
if(isOlder && possible_cycle){
|
|
||||||
// set our pendingAbort flag
|
|
||||||
cout << "notifyReceiveNack Setting Abort Pending Flag addr= " << addr << " ID = " << m_node << " possible_cycle = " << possible_cycle << " time = " << g_eventQueue_ptr->getTime() << endl;
|
|
||||||
m_abortPending = true;
|
|
||||||
assert(possible_cycle);
|
|
||||||
assert(isOlder);
|
|
||||||
}
|
|
||||||
|
|
||||||
// profile this nack
|
|
||||||
xact_mgr->profileNack(addr, IDToInt(L1CacheMachIDToProcessorNum(remote_id)), remote_timestamp, 0, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
void XactRequestGenerator::notifyReceiveNackFinal(const Address & physicalAddr) {
|
|
||||||
Address addr = physicalAddr;
|
|
||||||
addr.makeLineAddress();
|
|
||||||
TransactionManager * xact_mgr = transactionManager();
|
|
||||||
int local_timestamp = xact_mgr->getTimestamp(0);
|
|
||||||
bool possible_cycle = xact_mgr->possibleCycle(0);
|
|
||||||
|
|
||||||
// we should still have an active request
|
|
||||||
if(m_abortPending){
|
|
||||||
cout << "notifyReceiveNackFinal ABORTING addr= " << addr << " ID = " << m_node << " possible_cycle = " << possible_cycle << " time = " << g_eventQueue_ptr->getTime() << endl;
|
|
||||||
assert(possible_cycle);
|
|
||||||
|
|
||||||
// we abort
|
|
||||||
// Step 1: remove the aborting request from sequencer, and mark it as "Trap" in our request table if needed
|
|
||||||
// Note: by marking request as "Trap" we can simulate HW abort delay
|
|
||||||
switch (m_instructions[m_pc].getOpcode()){
|
|
||||||
case Opcode_LD:
|
|
||||||
sequencer()->readCallbackAbort(addr, 0);
|
|
||||||
break;
|
|
||||||
case Opcode_ST:
|
|
||||||
sequencer()->writeCallbackAbort(addr, 0);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
cout << "Invalid Opcode = " << m_instructions[m_pc].getOpcode() << endl;
|
|
||||||
ASSERT(0);
|
|
||||||
};
|
|
||||||
// Step 2: call the abort handler explicitly. If using software handler + trap aborts we wait until
|
|
||||||
// Simics transfers control to us again
|
|
||||||
// Note: it is impossible for this request to be a prefetch, so don't need that check
|
|
||||||
xact_mgr->abortTransaction(0, 0, -1 /*dummy remote ID*/, addr);
|
|
||||||
//reset the abort flag
|
|
||||||
m_abortPending = false;
|
|
||||||
}
|
|
||||||
else{
|
|
||||||
// retry the request
|
|
||||||
// figure out whether to retry transactional load or store
|
|
||||||
switch (m_instructions[m_pc].getOpcode()){
|
|
||||||
case Opcode_LD:
|
|
||||||
cout << "RETRYING LOAD " << addr << " of proc = " << m_node << " transactionLevel = " << xact_mgr->getTransactionLevel(0) << " time = " << g_eventQueue_ptr->getTime() << endl;
|
|
||||||
sequencer()->issueInterProcLoadRetryRequest(addr, 0);
|
|
||||||
break;
|
|
||||||
case Opcode_ST:
|
|
||||||
cout << "RETRYING STORE " << addr << " of proc = " << m_node << " transactionLevel = " << xact_mgr->getTransactionLevel(0) << " time = " << g_eventQueue_ptr->getTime() << endl;
|
|
||||||
sequencer()->issueInterProcStoreRetryRequest(addr, 0);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
cout << "Invalid Opcode = " << m_instructions[m_pc].getOpcode() << endl;
|
|
||||||
ASSERT(0);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,134 +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: XactRequestGenerator.h 1.4 05/07/07 10:35:32-05:00 kmoore@s0-30.cs.wisc.edu $
|
|
||||||
*
|
|
||||||
* Description:
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef XACTREQUESTGENERATOR_H
|
|
||||||
#define XACTREQUESTGENERATOR_H
|
|
||||||
|
|
||||||
#include "global.hh"
|
|
||||||
#include "mem/ruby/tester/RequestGenerator.hh"
|
|
||||||
#include "mem/ruby/common/Consumer.hh"
|
|
||||||
#include "mem/ruby/system/NodeID.hh"
|
|
||||||
#include "mem/ruby/common/Address.hh"
|
|
||||||
#include "TransactionManager.hh"
|
|
||||||
|
|
||||||
class Sequencer;
|
|
||||||
class SubBlock;
|
|
||||||
class SyntheticDriver;
|
|
||||||
class Instruction;
|
|
||||||
class TransactionManager;
|
|
||||||
|
|
||||||
#define MAX_ADDRESS 16777216
|
|
||||||
const int TESTER_MAX_DEPTH = 16;
|
|
||||||
|
|
||||||
enum XactRequestGeneratorStatus {
|
|
||||||
XactRequestGeneratorStatus_Waiting,
|
|
||||||
XactRequestGeneratorStatus_Ready,
|
|
||||||
XactRequestGeneratorStatus_Blocked,
|
|
||||||
XactRequestGeneratorStatus_Aborted,
|
|
||||||
XactRequestGeneratorStatus_Done
|
|
||||||
};
|
|
||||||
|
|
||||||
class XactRequestGenerator : public RequestGenerator {
|
|
||||||
public:
|
|
||||||
// Constructors
|
|
||||||
XactRequestGenerator(NodeID node, SyntheticDriver& driver);
|
|
||||||
|
|
||||||
// Destructor
|
|
||||||
~XactRequestGenerator();
|
|
||||||
|
|
||||||
// Public Methods
|
|
||||||
void wakeup();
|
|
||||||
void performCallback(NodeID proc, SubBlock& data);
|
|
||||||
void abortTransaction();
|
|
||||||
|
|
||||||
void print(ostream& out) const;
|
|
||||||
|
|
||||||
// For dealing with NACKs/retries
|
|
||||||
void notifySendNack(const Address & addr, uint64 remote_timestamp, const MachineID & remote_id);
|
|
||||||
void notifyReceiveNack(const Address & addr, uint64 remote_timestamp, const MachineID & remote_id);
|
|
||||||
void notifyReceiveNackFinal(const Address & addr);
|
|
||||||
private:
|
|
||||||
// Private Methods
|
|
||||||
int thinkTime() const;
|
|
||||||
int waitTime() const;
|
|
||||||
int holdTime() const;
|
|
||||||
void initiateBeginTransaction();
|
|
||||||
void initiateStore(Address a);
|
|
||||||
void initiateCommit();
|
|
||||||
void initiateInc(Address a);
|
|
||||||
void initiateLoad(Address a);
|
|
||||||
void initiateDone();
|
|
||||||
void pickAddress();
|
|
||||||
Sequencer* sequencer() const;
|
|
||||||
TransactionManager* transactionManager() const;
|
|
||||||
void execute();
|
|
||||||
void scheduleEvent(int time);
|
|
||||||
void checkCorrectness();
|
|
||||||
|
|
||||||
// Private copy constructor and assignment operator
|
|
||||||
XactRequestGenerator(const XactRequestGenerator& obj);
|
|
||||||
XactRequestGenerator& operator=(const XactRequestGenerator& obj);
|
|
||||||
|
|
||||||
void newTransaction(bool init);
|
|
||||||
void printPcStack(int depth);
|
|
||||||
|
|
||||||
// Data Members (m_ prefix)
|
|
||||||
SyntheticDriver& m_driver;
|
|
||||||
NodeID m_node;
|
|
||||||
XactRequestGeneratorStatus m_status;
|
|
||||||
int m_counter;
|
|
||||||
int m_size;
|
|
||||||
Time m_last_transition;
|
|
||||||
Address m_address;
|
|
||||||
|
|
||||||
Instruction *m_instructions;
|
|
||||||
int m_pc;
|
|
||||||
int pc_stack[TESTER_MAX_DEPTH];
|
|
||||||
bool m_transaction;
|
|
||||||
uint8 m_register;
|
|
||||||
uint8 * testArray;
|
|
||||||
//static uint8 dataArray[];
|
|
||||||
bool m_eventPending;
|
|
||||||
|
|
||||||
// for pending aborts
|
|
||||||
bool m_abortPending;
|
|
||||||
};
|
|
||||||
|
|
||||||
// Output operator declaration
|
|
||||||
ostream& operator<<(ostream& out, const XactRequestGenerator& obj);
|
|
||||||
|
|
||||||
// ******************* Definitions *******************
|
|
||||||
|
|
||||||
// Output operator definition
|
|
||||||
extern inline
|
|
||||||
ostream& operator<<(ostream& out, const XactRequestGenerator& obj)
|
|
||||||
{
|
|
||||||
obj.print(out);
|
|
||||||
out << flush;
|
|
||||||
return out;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif //XACTREQUESTGENERATOR_H
|
|
||||||
|
|
Loading…
Reference in a new issue