ruby: stats: use gem5's stats for cache and memory controllers
authorNilay Vaish <nilay@cs.wisc.edu>
Sun, 9 Jun 2013 12:29:59 +0000 (07:29 -0500)
committerNilay Vaish <nilay@cs.wisc.edu>
Sun, 9 Jun 2013 12:29:59 +0000 (07:29 -0500)
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.

src/mem/ruby/profiler/MemCntrlProfiler.cc
src/mem/ruby/profiler/MemCntrlProfiler.hh
src/mem/ruby/slicc_interface/AbstractController.cc
src/mem/ruby/slicc_interface/AbstractController.hh
src/mem/ruby/system/MemoryControl.hh
src/mem/ruby/system/RubyMemoryControl.cc
src/mem/ruby/system/RubyMemoryControl.hh
src/mem/slicc/ast/MachineAST.py
src/mem/slicc/symbols/StateMachine.py

index 632842a2e744857b521671bb702eb445cbe05bae..0cfc1e62987ad3f5e3364e47c0ff69b229798a06 100644 (file)
@@ -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, "");
+    }
+}
 
index a594e0d9661d963f81d9996f7372d138e3556308..56e283f5050b2bb74d30b02e0b977dbbc94edbca 100644 (file)
@@ -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;
index 6e99a72bbc841eec7dc93570340bc8d781ead567..930f3a70f6a11f2b91675bc0be654041157f5421 100644 (file)
@@ -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
index e2471777bae6c884219e0c334019cf93f9ea747c..079979bdf5cbba4751477e1ee8025d2180475294 100644 (file)
@@ -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__
index daa5b61fcc9d1105a10605e4a6618146cbb85a4c..6dc32b661d0bd6d93cef6594033db257c8077e72 100644 (file)
@@ -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;
index 5ffc60e2b26b18bb33f5fef67d7b72a73fb04a76..84126a8f5d82aac1862ca4296db2c489d522973d 100644 (file)
@@ -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()
 {
index d0dfa5b8da4725df48fb09646284413bd9fd6cbd..7be74583a35bd5d053a701a03439f52c7159f3a7 100644 (file)
@@ -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;
index c48d2aef177970a6f4b4b4748056ce0c200824ae..d494cb7cec3e799c147200f4179995c93be939c6 100644 (file)
@@ -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))
 
index c2ee42553b73dbb5db1f557f2c0d0eb2e5366020..a110092b640fecf9dee05e58b3087d8b903f39ca 100644 (file)
@@ -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 *******