ruby: stats: use gem5's stats for cache and memory controllers
This moves event and transition count statistics for cache controllers to
gem5's statistics. It does the same for the statistics associated with the
memory controller in ruby.
All the cache/directory/dma controllers individually collect the event and
transition counts. A callback function, collateStats(), has been added that
is invoked on the controller version 0 of each controller class. This
function adds all the individual controller statistics to a vector
variables. All the code for registering the statistical variables and
collating them is generated by SLICC. The patch removes the files
*_Profiler.{cc,hh} and *_ProfileDumper.{cc,hh} which were earlier used for
collecting and dumping statistics respectively.
This commit is contained in:
@@ -37,98 +37,12 @@ MemCntrlProfiler::MemCntrlProfiler(const string& description,
|
||||
m_banks_per_rank = banks_per_rank;
|
||||
m_ranks_per_dimm = ranks_per_dimm;
|
||||
m_dimms_per_channel = dimms_per_channel;
|
||||
|
||||
int totalBanks = banks_per_rank * ranks_per_dimm * dimms_per_channel;
|
||||
m_memBankCount.resize(totalBanks);
|
||||
|
||||
clearStats();
|
||||
}
|
||||
|
||||
MemCntrlProfiler::~MemCntrlProfiler()
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
MemCntrlProfiler::printStats(ostream& out) const
|
||||
{
|
||||
if (!m_memReq && !m_memRefresh) {
|
||||
out << "Memory Controller: " << m_description
|
||||
<< " no stats recorded." << endl
|
||||
<< endl
|
||||
<< endl;
|
||||
return;
|
||||
}
|
||||
|
||||
// if there's a memory controller at all
|
||||
uint64 total_stalls = m_memInputQ + m_memBankQ + m_memWaitCycles;
|
||||
double stallsPerReq = total_stalls * 1.0 / m_memReq;
|
||||
out << "Memory controller: " << m_description << ":" << endl;
|
||||
|
||||
// does not include refreshes
|
||||
out << " memory_total_requests: " << m_memReq << endl;
|
||||
out << " memory_reads: " << m_memRead << endl;
|
||||
out << " memory_writes: " << m_memWrite << endl;
|
||||
out << " memory_refreshes: " << m_memRefresh << endl;
|
||||
out << " memory_total_request_delays: " << total_stalls << endl;
|
||||
out << " memory_delays_per_request: " << stallsPerReq << endl;
|
||||
out << " memory_delays_in_input_queue: " << m_memInputQ << endl;
|
||||
out << " memory_delays_behind_head_of_bank_queue: "
|
||||
<< m_memBankQ << endl;
|
||||
out << " memory_delays_stalled_at_head_of_bank_queue: "
|
||||
<< m_memWaitCycles << endl;
|
||||
|
||||
// Note: The following "memory stalls" entries are a breakdown of
|
||||
// the cycles which already showed up in m_memWaitCycles. The
|
||||
// order is significant; it is the priority of attributing the
|
||||
// cycles. For example, bank_busy is before arbitration because
|
||||
// if the bank was busy, we didn't even check arbitration.
|
||||
// Note: "not old enough" means that since we grouped waiting
|
||||
// heads-of-queues into batches to avoid starvation, a request in
|
||||
// a newer batch didn't try to arbitrate yet because there are
|
||||
// older requests waiting.
|
||||
out << " memory_stalls_for_bank_busy: " << m_memBankBusy << endl;
|
||||
out << " memory_stalls_for_random_busy: " << m_memRandBusy << endl;
|
||||
out << " memory_stalls_for_anti_starvation: " << m_memNotOld << endl;
|
||||
out << " memory_stalls_for_arbitration: " << m_memArbWait << endl;
|
||||
out << " memory_stalls_for_bus: " << m_memBusBusy << endl;
|
||||
out << " memory_stalls_for_tfaw: " << m_memTfawBusy << endl;
|
||||
out << " memory_stalls_for_read_write_turnaround: "
|
||||
<< m_memReadWriteBusy << endl;
|
||||
out << " memory_stalls_for_read_read_turnaround: "
|
||||
<< m_memDataBusBusy << endl;
|
||||
out << " accesses_per_bank: ";
|
||||
|
||||
for (int bank = 0; bank < m_memBankCount.size(); bank++) {
|
||||
out << m_memBankCount[bank] << " ";
|
||||
}
|
||||
out << endl;
|
||||
out << endl;
|
||||
}
|
||||
|
||||
void
|
||||
MemCntrlProfiler::clearStats()
|
||||
{
|
||||
m_memReq = 0;
|
||||
m_memBankBusy = 0;
|
||||
m_memBusBusy = 0;
|
||||
m_memTfawBusy = 0;
|
||||
m_memReadWriteBusy = 0;
|
||||
m_memDataBusBusy = 0;
|
||||
m_memRefresh = 0;
|
||||
m_memRead = 0;
|
||||
m_memWrite = 0;
|
||||
m_memWaitCycles = 0;
|
||||
m_memInputQ = 0;
|
||||
m_memBankQ = 0;
|
||||
m_memArbWait = 0;
|
||||
m_memRandBusy = 0;
|
||||
m_memNotOld = 0;
|
||||
|
||||
for (int bank = 0; bank < m_memBankCount.size(); bank++) {
|
||||
m_memBankCount[bank] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
MemCntrlProfiler::profileMemReq(int bank)
|
||||
{
|
||||
@@ -220,4 +134,133 @@ MemCntrlProfiler::profileMemNotOld()
|
||||
m_memNotOld++;
|
||||
}
|
||||
|
||||
void
|
||||
MemCntrlProfiler::regStats()
|
||||
{
|
||||
m_memReq
|
||||
.name(m_description + ".memReq")
|
||||
.desc("Total number of memory requests")
|
||||
.flags(Stats::nozero)
|
||||
;
|
||||
|
||||
m_memRead
|
||||
.name(m_description + ".memRead")
|
||||
.desc("Number of memory reads")
|
||||
.flags(Stats::nozero)
|
||||
;
|
||||
|
||||
m_memWrite
|
||||
.name(m_description + ".memWrite")
|
||||
.desc("Number of memory writes")
|
||||
.flags(Stats::nozero)
|
||||
;
|
||||
|
||||
m_memRefresh
|
||||
.name(m_description + ".memRefresh")
|
||||
.desc("Number of memory refreshes")
|
||||
.flags(Stats::nozero)
|
||||
;
|
||||
|
||||
m_memInputQ
|
||||
.name(m_description + ".memInputQ")
|
||||
.desc("Delay in the input queue")
|
||||
.flags(Stats::nozero)
|
||||
;
|
||||
|
||||
m_memBankQ
|
||||
.name(m_description + ".memBankQ")
|
||||
.desc("Delay behind the head of the bank queue")
|
||||
.flags(Stats::nozero)
|
||||
;
|
||||
|
||||
m_memWaitCycles
|
||||
.name(m_description + ".memWaitCycles")
|
||||
.desc("Delay stalled at the head of the bank queue")
|
||||
.flags(Stats::nozero)
|
||||
;
|
||||
|
||||
m_totalStalls
|
||||
.name(m_description + ".totalStalls")
|
||||
.desc("Total number of stall cycles")
|
||||
.flags(Stats::nozero)
|
||||
;
|
||||
|
||||
m_totalStalls = m_memInputQ + m_memBankQ + m_memWaitCycles;
|
||||
|
||||
m_stallsPerReq
|
||||
.name(m_description + ".stallsPerReq")
|
||||
.desc("Expected number of stall cycles per request")
|
||||
.flags(Stats::nozero)
|
||||
;
|
||||
|
||||
m_stallsPerReq = m_totalStalls / m_memReq;
|
||||
|
||||
// Note: The following "memory stalls" entries are a breakdown of
|
||||
// the cycles which already showed up in m_memWaitCycles. The
|
||||
// order is significant; it is the priority of attributing the
|
||||
// cycles. For example, bank_busy is before arbitration because
|
||||
// if the bank was busy, we didn't even check arbitration.
|
||||
// Note: "not old enough" means that since we grouped waiting
|
||||
// heads-of-queues into batches to avoid starvation, a request in
|
||||
// a newer batch didn't try to arbitrate yet because there are
|
||||
// older requests waiting.
|
||||
m_memBankBusy
|
||||
.name(m_description + ".memBankBusy")
|
||||
.desc("memory stalls due to busy bank")
|
||||
.flags(Stats::nozero)
|
||||
;
|
||||
|
||||
m_memRandBusy
|
||||
.name(m_description + ".memRandBusy")
|
||||
.desc("memory stalls due to busy random")
|
||||
.flags(Stats::nozero)
|
||||
;
|
||||
|
||||
m_memNotOld
|
||||
.name(m_description + ".memNotOld")
|
||||
.desc("memory stalls due to anti starvation")
|
||||
.flags(Stats::nozero)
|
||||
;
|
||||
|
||||
m_memArbWait
|
||||
.name(m_description + ".memArbWait")
|
||||
.desc("memory stalls due to arbitration")
|
||||
.flags(Stats::nozero)
|
||||
;
|
||||
|
||||
m_memBusBusy
|
||||
.name(m_description + ".memBusBusy")
|
||||
.desc("memory stalls due to busy bus")
|
||||
.flags(Stats::nozero)
|
||||
;
|
||||
|
||||
m_memTfawBusy
|
||||
.name(m_description + ".memTfawBusy")
|
||||
.desc("memory stalls for Tfaw")
|
||||
.flags(Stats::nozero)
|
||||
;
|
||||
|
||||
m_memReadWriteBusy
|
||||
.name(m_description + ".memReadWriteBusy")
|
||||
.desc("memory stalls due to read write turnaround")
|
||||
.flags(Stats::nozero)
|
||||
;
|
||||
|
||||
m_memDataBusBusy
|
||||
.name(m_description + ".memDataBusBusy")
|
||||
.desc("memory stalls due to read read turnaround")
|
||||
.flags(Stats::nozero)
|
||||
;
|
||||
|
||||
int totalBanks = m_banks_per_rank * m_ranks_per_dimm * m_dimms_per_channel;
|
||||
m_memBankCount
|
||||
.init(totalBanks)
|
||||
.name(m_description + ".memBankCount")
|
||||
.desc("Number of accesses per bank")
|
||||
.flags(Stats::pdf | Stats::total|Stats::oneline)
|
||||
;
|
||||
for (int i = 0; i < totalBanks; i++) {
|
||||
m_memBankCount.subname(i, "");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -33,6 +33,7 @@
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "base/statistics.hh"
|
||||
#include "mem/ruby/common/TypeDefines.hh"
|
||||
|
||||
class MemCntrlProfiler
|
||||
@@ -42,8 +43,7 @@ class MemCntrlProfiler
|
||||
int ranks_per_dimm, int dimms_per_channel);
|
||||
~MemCntrlProfiler();
|
||||
|
||||
void printStats(std::ostream& out) const;
|
||||
void clearStats();
|
||||
void regStats();
|
||||
|
||||
void profileMemReq(int bank);
|
||||
void profileMemBankBusy();
|
||||
@@ -69,22 +69,27 @@ private:
|
||||
MemCntrlProfiler& operator=(const MemCntrlProfiler& obj);
|
||||
|
||||
std::string m_description;
|
||||
uint64 m_memReq;
|
||||
uint64 m_memBankBusy;
|
||||
uint64 m_memBusBusy;
|
||||
uint64 m_memTfawBusy;
|
||||
uint64 m_memReadWriteBusy;
|
||||
uint64 m_memDataBusBusy;
|
||||
uint64 m_memRefresh;
|
||||
uint64 m_memRead;
|
||||
uint64 m_memWrite;
|
||||
uint64 m_memWaitCycles;
|
||||
uint64 m_memInputQ;
|
||||
uint64 m_memBankQ;
|
||||
uint64 m_memArbWait;
|
||||
uint64 m_memRandBusy;
|
||||
uint64 m_memNotOld;
|
||||
std::vector<uint64> m_memBankCount;
|
||||
Stats::Scalar m_memReq;
|
||||
Stats::Scalar m_memRead;
|
||||
Stats::Scalar m_memWrite;
|
||||
Stats::Scalar m_memRefresh;
|
||||
|
||||
Stats::Scalar m_memWaitCycles;
|
||||
Stats::Scalar m_memInputQ;
|
||||
Stats::Scalar m_memBankQ;
|
||||
Stats::Formula m_totalStalls;
|
||||
Stats::Formula m_stallsPerReq;
|
||||
|
||||
Stats::Scalar m_memBankBusy;
|
||||
Stats::Scalar m_memBusBusy;
|
||||
Stats::Scalar m_memTfawBusy;
|
||||
Stats::Scalar m_memReadWriteBusy;
|
||||
Stats::Scalar m_memDataBusBusy;
|
||||
Stats::Scalar m_memArbWait;
|
||||
Stats::Scalar m_memRandBusy;
|
||||
Stats::Scalar m_memNotOld;
|
||||
Stats::Vector m_memBankCount;
|
||||
|
||||
int m_banks_per_rank;
|
||||
int m_ranks_per_dimm;
|
||||
int m_dimms_per_channel;
|
||||
|
||||
@@ -40,6 +40,12 @@ AbstractController::AbstractController(const Params *p)
|
||||
m_recycle_latency = p->recycle_latency;
|
||||
m_number_of_TBEs = p->number_of_TBEs;
|
||||
m_is_blocking = false;
|
||||
|
||||
if (m_version == 0) {
|
||||
// Combine the statistics from all controllers
|
||||
// of this particular type.
|
||||
Stats::registerDumpCallback(new StatsCallback(this));
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
|
||||
@@ -32,6 +32,7 @@
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
|
||||
#include "base/callback.hh"
|
||||
#include "mem/protocol/AccessPermission.hh"
|
||||
#include "mem/ruby/buffers/MessageBuffer.hh"
|
||||
#include "mem/ruby/common/Address.hh"
|
||||
@@ -54,6 +55,7 @@ class AbstractController : public ClockedObject, public Consumer
|
||||
AbstractController(const Params *p);
|
||||
void init();
|
||||
const Params *params() const { return (const Params *)_params; }
|
||||
|
||||
virtual MessageBuffer* getMandatoryQueue() const = 0;
|
||||
virtual const int & getVersion() const = 0;
|
||||
virtual const std::string toString() const = 0; // returns text version of
|
||||
@@ -68,8 +70,9 @@ class AbstractController : public ClockedObject, public Consumer
|
||||
virtual void print(std::ostream & out) const = 0;
|
||||
virtual void printStats(std::ostream & out) const = 0;
|
||||
virtual void wakeup() = 0;
|
||||
// virtual void dumpStats(std::ostream & out) = 0;
|
||||
virtual void clearStats() = 0;
|
||||
virtual void regStats() = 0;
|
||||
|
||||
virtual void recordCacheTrace(int cntrl, CacheRecorder* tr) = 0;
|
||||
virtual Sequencer* getSequencer() const = 0;
|
||||
|
||||
@@ -86,6 +89,12 @@ class AbstractController : public ClockedObject, public Consumer
|
||||
virtual void enqueuePrefetch(const Address&, const RubyRequestType&)
|
||||
{ fatal("Prefetches not implemented!");}
|
||||
|
||||
//! Function for collating statistics from all the controllers of this
|
||||
//! particular type. This function should only be called from the
|
||||
//! version 0 of this controller type.
|
||||
virtual void collateStats()
|
||||
{fatal("collateStats() should be overridden!");}
|
||||
|
||||
public:
|
||||
MachineID getMachineID() const { return m_machineID; }
|
||||
uint64_t getFullyBusyCycles() const { return m_fully_busy_cycles; }
|
||||
@@ -154,6 +163,24 @@ class AbstractController : public ClockedObject, public Consumer
|
||||
//! cares for
|
||||
Histogram m_delayHistogram;
|
||||
std::vector<Histogram> m_delayVCHistogram;
|
||||
|
||||
//! Callback class used for collating statistics from all the
|
||||
//! controller of this type.
|
||||
class StatsCallback : public Callback
|
||||
{
|
||||
private:
|
||||
AbstractController *ctr;
|
||||
|
||||
public:
|
||||
virtual ~StatsCallback() {}
|
||||
|
||||
StatsCallback(AbstractController *_ctr)
|
||||
: ctr(_ctr)
|
||||
{
|
||||
}
|
||||
|
||||
void process() {ctr->collateStats();}
|
||||
};
|
||||
};
|
||||
|
||||
#endif // __MEM_RUBY_SLICC_INTERFACE_ABSTRACTCONTROLLER_HH__
|
||||
|
||||
@@ -75,9 +75,6 @@ class MemoryControl : public ClockedObject, public Consumer
|
||||
virtual bool areNSlotsAvailable(int n) = 0; // infinite queue length
|
||||
|
||||
virtual void print(std::ostream& out) const = 0;
|
||||
virtual void clearStats() const = 0;
|
||||
virtual void printStats(std::ostream& out) const = 0;
|
||||
|
||||
virtual void regStats() {};
|
||||
|
||||
virtual const int getChannel(const physical_address_t addr) const = 0;
|
||||
|
||||
@@ -221,6 +221,7 @@ RubyMemoryControl::init()
|
||||
m_tfaw_count[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
RubyMemoryControl::reset()
|
||||
{
|
||||
@@ -359,18 +360,6 @@ RubyMemoryControl::print(ostream& out) const
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
RubyMemoryControl::clearStats() const
|
||||
{
|
||||
m_profiler_ptr->clearStats();
|
||||
}
|
||||
|
||||
void
|
||||
RubyMemoryControl::printStats(ostream& out) const
|
||||
{
|
||||
m_profiler_ptr->printStats(out);
|
||||
}
|
||||
|
||||
// Queue up a completed request to send back to directory
|
||||
void
|
||||
RubyMemoryControl::enqueueToDirectory(MemoryNode req, Cycles latency)
|
||||
@@ -789,6 +778,12 @@ RubyMemoryControl::functionalWriteBuffers(Packet *pkt)
|
||||
return num_functional_writes;
|
||||
}
|
||||
|
||||
void
|
||||
RubyMemoryControl::regStats()
|
||||
{
|
||||
m_profiler_ptr->regStats();
|
||||
}
|
||||
|
||||
RubyMemoryControl *
|
||||
RubyMemoryControlParams::create()
|
||||
{
|
||||
|
||||
@@ -81,8 +81,7 @@ class RubyMemoryControl : public MemoryControl
|
||||
bool areNSlotsAvailable(int n) { return true; }; // infinite queue length
|
||||
|
||||
void print(std::ostream& out) const;
|
||||
void clearStats() const;
|
||||
void printStats(std::ostream& out) const;
|
||||
void regStats();
|
||||
|
||||
const int getBank(const physical_address_t addr) const;
|
||||
const int getRank(const physical_address_t addr) const;
|
||||
|
||||
@@ -44,10 +44,6 @@ class MachineAST(DeclAST):
|
||||
s = set(('%s_Controller.cc' % self.ident,
|
||||
'%s_Controller.hh' % self.ident,
|
||||
'%s_Controller.py' % self.ident,
|
||||
'%s_Profiler.cc' % self.ident,
|
||||
'%s_Profiler.hh' % self.ident,
|
||||
'%s_ProfileDumper.cc' % self.ident,
|
||||
'%s_ProfileDumper.hh' % self.ident,
|
||||
'%s_Transitions.cc' % self.ident,
|
||||
'%s_Wakeup.cc' % self.ident))
|
||||
|
||||
|
||||
@@ -173,10 +173,6 @@ class StateMachine(Symbol):
|
||||
self.printControllerCC(path, includes)
|
||||
self.printCSwitch(path)
|
||||
self.printCWakeup(path, includes)
|
||||
self.printProfilerCC(path)
|
||||
self.printProfilerHH(path)
|
||||
self.printProfileDumperCC(path)
|
||||
self.printProfileDumperHH(path)
|
||||
|
||||
def printControllerPython(self, path):
|
||||
code = self.symtab.codeFormatter()
|
||||
@@ -228,8 +224,6 @@ class $py_ident(RubyController):
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
|
||||
#include "mem/protocol/${ident}_ProfileDumper.hh"
|
||||
#include "mem/protocol/${ident}_Profiler.hh"
|
||||
#include "mem/protocol/TransitionResult.hh"
|
||||
#include "mem/protocol/Types.hh"
|
||||
#include "mem/ruby/common/Consumer.hh"
|
||||
@@ -263,10 +257,14 @@ class $c_ident : public AbstractController
|
||||
const std::string toString() const;
|
||||
const std::string getName() const;
|
||||
void initNetworkPtr(Network* net_ptr) { m_net_ptr = net_ptr; }
|
||||
|
||||
void print(std::ostream& out) const;
|
||||
void wakeup();
|
||||
void printStats(std::ostream& out) const;
|
||||
void clearStats();
|
||||
void regStats();
|
||||
void collateStats();
|
||||
|
||||
void blockOnQueue(Address addr, MessageBuffer* port);
|
||||
void unblock(Address addr);
|
||||
void recordCacheTrace(int cntrl, CacheRecorder* tr);
|
||||
@@ -275,6 +273,12 @@ class $c_ident : public AbstractController
|
||||
bool functionalReadBuffers(PacketPtr&);
|
||||
uint32_t functionalWriteBuffers(PacketPtr&);
|
||||
|
||||
void countTransition(${ident}_State state, ${ident}_Event event);
|
||||
void possibleTransition(${ident}_State state, ${ident}_Event event);
|
||||
uint64 getEventCount(${ident}_Event event);
|
||||
bool isPossible(${ident}_State state, ${ident}_Event event);
|
||||
uint64 getTransitionCount(${ident}_State state, ${ident}_Event event);
|
||||
|
||||
private:
|
||||
''')
|
||||
|
||||
@@ -319,8 +323,12 @@ TransitionResult doTransitionWorker(${ident}_Event event,
|
||||
code('''
|
||||
const Address& addr);
|
||||
|
||||
static ${ident}_ProfileDumper s_profileDumper;
|
||||
${ident}_Profiler m_profiler;
|
||||
int m_counters[${ident}_State_NUM][${ident}_Event_NUM];
|
||||
int m_event_counters[${ident}_Event_NUM];
|
||||
bool m_possible[${ident}_State_NUM][${ident}_Event_NUM];
|
||||
|
||||
static std::vector<Stats::Vector *> eventVec;
|
||||
static std::vector<std::vector<Stats::Vector *> > transVec;
|
||||
static int m_num_controllers;
|
||||
|
||||
// Internal functions
|
||||
@@ -440,7 +448,8 @@ ${c_ident}Params::create()
|
||||
}
|
||||
|
||||
int $c_ident::m_num_controllers = 0;
|
||||
${ident}_ProfileDumper $c_ident::s_profileDumper;
|
||||
std::vector<Stats::Vector *> $c_ident::eventVec;
|
||||
std::vector<std::vector<Stats::Vector *> > $c_ident::transVec;
|
||||
|
||||
// for adding information to the protocol debug trace
|
||||
stringstream ${ident}_transitionComment;
|
||||
@@ -520,6 +529,16 @@ m_${{var.c_ident}}_ptr->setSender(this);
|
||||
code('''
|
||||
if (p->peer != NULL)
|
||||
connectWithPeer(p->peer);
|
||||
|
||||
for (int state = 0; state < ${ident}_State_NUM; state++) {
|
||||
for (int event = 0; event < ${ident}_Event_NUM; event++) {
|
||||
m_possible[state][event] = false;
|
||||
m_counters[state][event] = 0;
|
||||
}
|
||||
}
|
||||
for (int event = 0; event < ${ident}_Event_NUM; event++) {
|
||||
m_event_counters[event] = 0;
|
||||
}
|
||||
''')
|
||||
code.dedent()
|
||||
code('''
|
||||
@@ -528,17 +547,13 @@ if (p->peer != NULL)
|
||||
void
|
||||
$c_ident::init()
|
||||
{
|
||||
MachineType machine_type;
|
||||
int base;
|
||||
machine_type = string_to_MachineType("${{var.machine.ident}}");
|
||||
base = MachineType_base_number(machine_type);
|
||||
MachineType machine_type = string_to_MachineType("${{var.machine.ident}}");
|
||||
int base = MachineType_base_number(machine_type);
|
||||
|
||||
m_machineID.type = MachineType_${ident};
|
||||
m_machineID.num = m_version;
|
||||
|
||||
// initialize objects
|
||||
m_profiler.setVersion(m_version);
|
||||
s_profileDumper.registerProfiler(&m_profiler);
|
||||
|
||||
''')
|
||||
|
||||
@@ -675,7 +690,7 @@ $vid->setDescription("[Version " + to_string(m_version) + ", ${ident}, name=${{v
|
||||
if not stall:
|
||||
state = "%s_State_%s" % (self.ident, trans.state.ident)
|
||||
event = "%s_Event_%s" % (self.ident, trans.event.ident)
|
||||
code('m_profiler.possibleTransition($state, $event);')
|
||||
code('possibleTransition($state, $event);')
|
||||
|
||||
code.dedent()
|
||||
code('''
|
||||
@@ -701,6 +716,107 @@ $vid->setDescription("[Version " + to_string(m_version) + ", ${ident}, name=${{v
|
||||
seq_ident = "m_%s_ptr" % param.name
|
||||
|
||||
code('''
|
||||
|
||||
void
|
||||
$c_ident::regStats()
|
||||
{
|
||||
if (m_version == 0) {
|
||||
for (${ident}_Event event = ${ident}_Event_FIRST;
|
||||
event < ${ident}_Event_NUM; ++event) {
|
||||
Stats::Vector *t = new Stats::Vector();
|
||||
t->init(m_num_controllers);
|
||||
t->name(name() + "." + ${ident}_Event_to_string(event));
|
||||
t->flags(Stats::pdf | Stats::total | Stats::oneline |
|
||||
Stats::nozero);
|
||||
|
||||
eventVec.push_back(t);
|
||||
}
|
||||
|
||||
for (${ident}_State state = ${ident}_State_FIRST;
|
||||
state < ${ident}_State_NUM; ++state) {
|
||||
|
||||
transVec.push_back(std::vector<Stats::Vector *>());
|
||||
|
||||
for (${ident}_Event event = ${ident}_Event_FIRST;
|
||||
event < ${ident}_Event_NUM; ++event) {
|
||||
|
||||
Stats::Vector *t = new Stats::Vector();
|
||||
t->init(m_num_controllers);
|
||||
t->name(name() + "." + ${ident}_State_to_string(state) +
|
||||
"." + ${ident}_Event_to_string(event));
|
||||
|
||||
t->flags(Stats::pdf | Stats::total | Stats::oneline |
|
||||
Stats::nozero);
|
||||
transVec[state].push_back(t);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
$c_ident::collateStats()
|
||||
{
|
||||
for (${ident}_Event event = ${ident}_Event_FIRST;
|
||||
event < ${ident}_Event_NUM; ++event) {
|
||||
for (unsigned int i = 0; i < m_num_controllers; ++i) {
|
||||
std::map<uint32_t, AbstractController *>::iterator it =
|
||||
g_abs_controls[MachineType_${ident}].find(i);
|
||||
assert(it != g_abs_controls[MachineType_${ident}].end());
|
||||
(*eventVec[event])[i] =
|
||||
(($c_ident *)(*it).second)->getEventCount(event);
|
||||
}
|
||||
}
|
||||
|
||||
for (${ident}_State state = ${ident}_State_FIRST;
|
||||
state < ${ident}_State_NUM; ++state) {
|
||||
|
||||
for (${ident}_Event event = ${ident}_Event_FIRST;
|
||||
event < ${ident}_Event_NUM; ++event) {
|
||||
|
||||
for (unsigned int i = 0; i < m_num_controllers; ++i) {
|
||||
std::map<uint32_t, AbstractController *>::iterator it =
|
||||
g_abs_controls[MachineType_${ident}].find(i);
|
||||
assert(it != g_abs_controls[MachineType_${ident}].end());
|
||||
(*transVec[state][event])[i] =
|
||||
(($c_ident *)(*it).second)->getTransitionCount(state, event);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
$c_ident::countTransition(${ident}_State state, ${ident}_Event event)
|
||||
{
|
||||
assert(m_possible[state][event]);
|
||||
m_counters[state][event]++;
|
||||
m_event_counters[event]++;
|
||||
}
|
||||
void
|
||||
$c_ident::possibleTransition(${ident}_State state,
|
||||
${ident}_Event event)
|
||||
{
|
||||
m_possible[state][event] = true;
|
||||
}
|
||||
|
||||
uint64
|
||||
$c_ident::getEventCount(${ident}_Event event)
|
||||
{
|
||||
return m_event_counters[event];
|
||||
}
|
||||
|
||||
bool
|
||||
$c_ident::isPossible(${ident}_State state, ${ident}_Event event)
|
||||
{
|
||||
return m_possible[state][event];
|
||||
}
|
||||
|
||||
uint64
|
||||
$c_ident::getTransitionCount(${ident}_State state,
|
||||
${ident}_Event event)
|
||||
{
|
||||
return m_counters[state][event];
|
||||
}
|
||||
|
||||
int
|
||||
$c_ident::getNumControllers()
|
||||
{
|
||||
@@ -768,30 +884,25 @@ $c_ident::printStats(ostream& out) const
|
||||
# them. Print out these stats before dumping state transition stats.
|
||||
#
|
||||
for param in self.config_parameters:
|
||||
if param.type_ast.type.ident == "DirectoryMemory" or \
|
||||
param.type_ast.type.ident == "MemoryControl":
|
||||
if param.type_ast.type.ident == "DirectoryMemory":
|
||||
assert(param.pointer)
|
||||
code(' m_${{param.ident}}_ptr->printStats(out);')
|
||||
|
||||
code('''
|
||||
if (m_version == 0) {
|
||||
s_profileDumper.dumpStats(out);
|
||||
}
|
||||
}
|
||||
|
||||
void $c_ident::clearStats() {
|
||||
''')
|
||||
#
|
||||
# Cache and Memory Controllers have specific profilers associated with
|
||||
# them. These stats must be cleared too.
|
||||
#
|
||||
for param in self.config_parameters:
|
||||
if param.type_ast.type.ident == "MemoryControl":
|
||||
assert(param.pointer)
|
||||
code(' m_${{param.ident}}_ptr->clearStats();')
|
||||
void $c_ident::clearStats()
|
||||
{
|
||||
for (int state = 0; state < ${ident}_State_NUM; state++) {
|
||||
for (int event = 0; event < ${ident}_Event_NUM; event++) {
|
||||
m_counters[state][event] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
for (int event = 0; event < ${ident}_Event_NUM; event++) {
|
||||
m_event_counters[event] = 0;
|
||||
}
|
||||
|
||||
code('''
|
||||
m_profiler.clearStats();
|
||||
AbstractController::clearStats();
|
||||
}
|
||||
''')
|
||||
@@ -1130,7 +1241,7 @@ ${ident}_Controller::doTransition(${ident}_Event event,
|
||||
if (result == TransitionResult_Valid) {
|
||||
DPRINTF(RubyGenerated, "next_state: %s\\n",
|
||||
${ident}_State_to_string(next_state));
|
||||
m_profiler.countTransition(state, event);
|
||||
countTransition(state, event);
|
||||
DPRINTFR(ProtocolTrace, "%15d %3s %10s%20s %6s>%-6s %s %s\\n",
|
||||
curTick(), m_version, "${ident}",
|
||||
${ident}_Event_to_string(event),
|
||||
@@ -1292,231 +1403,6 @@ if (!checkResourceAvailable(%s_RequestType_%s, addr)) {
|
||||
''')
|
||||
code.write(path, "%s_Transitions.cc" % self.ident)
|
||||
|
||||
def printProfileDumperHH(self, path):
|
||||
code = self.symtab.codeFormatter()
|
||||
ident = self.ident
|
||||
|
||||
code('''
|
||||
// Auto generated C++ code started by $__file__:$__line__
|
||||
// ${ident}: ${{self.short}}
|
||||
|
||||
#ifndef __${ident}_PROFILE_DUMPER_HH__
|
||||
#define __${ident}_PROFILE_DUMPER_HH__
|
||||
|
||||
#include <cassert>
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
|
||||
#include "${ident}_Event.hh"
|
||||
#include "${ident}_Profiler.hh"
|
||||
|
||||
typedef std::vector<${ident}_Profiler *> ${ident}_profilers;
|
||||
|
||||
class ${ident}_ProfileDumper
|
||||
{
|
||||
public:
|
||||
${ident}_ProfileDumper();
|
||||
void registerProfiler(${ident}_Profiler* profiler);
|
||||
void dumpStats(std::ostream& out) const;
|
||||
|
||||
private:
|
||||
${ident}_profilers m_profilers;
|
||||
};
|
||||
|
||||
#endif // __${ident}_PROFILE_DUMPER_HH__
|
||||
''')
|
||||
code.write(path, "%s_ProfileDumper.hh" % self.ident)
|
||||
|
||||
def printProfileDumperCC(self, path):
|
||||
code = self.symtab.codeFormatter()
|
||||
ident = self.ident
|
||||
|
||||
code('''
|
||||
// Auto generated C++ code started by $__file__:$__line__
|
||||
// ${ident}: ${{self.short}}
|
||||
|
||||
#include "mem/protocol/${ident}_ProfileDumper.hh"
|
||||
|
||||
${ident}_ProfileDumper::${ident}_ProfileDumper()
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
${ident}_ProfileDumper::registerProfiler(${ident}_Profiler* profiler)
|
||||
{
|
||||
if (profiler->getVersion() >= m_profilers.size())
|
||||
m_profilers.resize(profiler->getVersion() + 1);
|
||||
m_profilers[profiler->getVersion()] = profiler;
|
||||
}
|
||||
|
||||
void
|
||||
${ident}_ProfileDumper::dumpStats(std::ostream& out) const
|
||||
{
|
||||
out << " --- ${ident} ---\\n";
|
||||
out << " - Event Counts -\\n";
|
||||
for (${ident}_Event event = ${ident}_Event_FIRST;
|
||||
event < ${ident}_Event_NUM;
|
||||
++event) {
|
||||
out << (${ident}_Event) event << " [";
|
||||
uint64 total = 0;
|
||||
for (int i = 0; i < m_profilers.size(); i++) {
|
||||
out << m_profilers[i]->getEventCount(event) << " ";
|
||||
total += m_profilers[i]->getEventCount(event);
|
||||
}
|
||||
out << "] " << total << "\\n";
|
||||
}
|
||||
out << "\\n";
|
||||
out << " - Transitions -\\n";
|
||||
for (${ident}_State state = ${ident}_State_FIRST;
|
||||
state < ${ident}_State_NUM;
|
||||
++state) {
|
||||
for (${ident}_Event event = ${ident}_Event_FIRST;
|
||||
event < ${ident}_Event_NUM;
|
||||
++event) {
|
||||
if (m_profilers[0]->isPossible(state, event)) {
|
||||
out << (${ident}_State) state << " "
|
||||
<< (${ident}_Event) event << " [";
|
||||
uint64 total = 0;
|
||||
for (int i = 0; i < m_profilers.size(); i++) {
|
||||
out << m_profilers[i]->getTransitionCount(state, event) << " ";
|
||||
total += m_profilers[i]->getTransitionCount(state, event);
|
||||
}
|
||||
out << "] " << total << "\\n";
|
||||
}
|
||||
}
|
||||
out << "\\n";
|
||||
}
|
||||
}
|
||||
''')
|
||||
code.write(path, "%s_ProfileDumper.cc" % self.ident)
|
||||
|
||||
def printProfilerHH(self, path):
|
||||
code = self.symtab.codeFormatter()
|
||||
ident = self.ident
|
||||
|
||||
code('''
|
||||
// Auto generated C++ code started by $__file__:$__line__
|
||||
// ${ident}: ${{self.short}}
|
||||
|
||||
#ifndef __${ident}_PROFILER_HH__
|
||||
#define __${ident}_PROFILER_HH__
|
||||
|
||||
#include <cassert>
|
||||
#include <iostream>
|
||||
|
||||
#include "mem/protocol/${ident}_Event.hh"
|
||||
#include "mem/protocol/${ident}_State.hh"
|
||||
#include "mem/ruby/common/TypeDefines.hh"
|
||||
|
||||
class ${ident}_Profiler
|
||||
{
|
||||
public:
|
||||
${ident}_Profiler();
|
||||
void setVersion(int version);
|
||||
int getVersion();
|
||||
void countTransition(${ident}_State state, ${ident}_Event event);
|
||||
void possibleTransition(${ident}_State state, ${ident}_Event event);
|
||||
uint64 getEventCount(${ident}_Event event);
|
||||
bool isPossible(${ident}_State state, ${ident}_Event event);
|
||||
uint64 getTransitionCount(${ident}_State state, ${ident}_Event event);
|
||||
void clearStats();
|
||||
|
||||
private:
|
||||
int m_counters[${ident}_State_NUM][${ident}_Event_NUM];
|
||||
int m_event_counters[${ident}_Event_NUM];
|
||||
bool m_possible[${ident}_State_NUM][${ident}_Event_NUM];
|
||||
int m_version;
|
||||
};
|
||||
|
||||
#endif // __${ident}_PROFILER_HH__
|
||||
''')
|
||||
code.write(path, "%s_Profiler.hh" % self.ident)
|
||||
|
||||
def printProfilerCC(self, path):
|
||||
code = self.symtab.codeFormatter()
|
||||
ident = self.ident
|
||||
|
||||
code('''
|
||||
// Auto generated C++ code started by $__file__:$__line__
|
||||
// ${ident}: ${{self.short}}
|
||||
|
||||
#include <cassert>
|
||||
|
||||
#include "mem/protocol/${ident}_Profiler.hh"
|
||||
|
||||
${ident}_Profiler::${ident}_Profiler()
|
||||
{
|
||||
for (int state = 0; state < ${ident}_State_NUM; state++) {
|
||||
for (int event = 0; event < ${ident}_Event_NUM; event++) {
|
||||
m_possible[state][event] = false;
|
||||
m_counters[state][event] = 0;
|
||||
}
|
||||
}
|
||||
for (int event = 0; event < ${ident}_Event_NUM; event++) {
|
||||
m_event_counters[event] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
${ident}_Profiler::setVersion(int version)
|
||||
{
|
||||
m_version = version;
|
||||
}
|
||||
|
||||
int
|
||||
${ident}_Profiler::getVersion()
|
||||
{
|
||||
return m_version;
|
||||
}
|
||||
|
||||
void
|
||||
${ident}_Profiler::clearStats()
|
||||
{
|
||||
for (int state = 0; state < ${ident}_State_NUM; state++) {
|
||||
for (int event = 0; event < ${ident}_Event_NUM; event++) {
|
||||
m_counters[state][event] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
for (int event = 0; event < ${ident}_Event_NUM; event++) {
|
||||
m_event_counters[event] = 0;
|
||||
}
|
||||
}
|
||||
void
|
||||
${ident}_Profiler::countTransition(${ident}_State state, ${ident}_Event event)
|
||||
{
|
||||
assert(m_possible[state][event]);
|
||||
m_counters[state][event]++;
|
||||
m_event_counters[event]++;
|
||||
}
|
||||
void
|
||||
${ident}_Profiler::possibleTransition(${ident}_State state,
|
||||
${ident}_Event event)
|
||||
{
|
||||
m_possible[state][event] = true;
|
||||
}
|
||||
|
||||
uint64
|
||||
${ident}_Profiler::getEventCount(${ident}_Event event)
|
||||
{
|
||||
return m_event_counters[event];
|
||||
}
|
||||
|
||||
bool
|
||||
${ident}_Profiler::isPossible(${ident}_State state, ${ident}_Event event)
|
||||
{
|
||||
return m_possible[state][event];
|
||||
}
|
||||
|
||||
uint64
|
||||
${ident}_Profiler::getTransitionCount(${ident}_State state,
|
||||
${ident}_Event event)
|
||||
{
|
||||
return m_counters[state][event];
|
||||
}
|
||||
|
||||
''')
|
||||
code.write(path, "%s_Profiler.cc" % self.ident)
|
||||
|
||||
# **************************
|
||||
# ******* HTML Files *******
|
||||
|
||||
Reference in New Issue
Block a user