summaryrefslogtreecommitdiff
path: root/src/base/cp_annotate.hh
diff options
context:
space:
mode:
authorAli Saidi <saidi@eecs.umich.edu>2009-02-26 19:29:17 -0500
committerAli Saidi <saidi@eecs.umich.edu>2009-02-26 19:29:17 -0500
commit6fd4bc34a154601ba0a74e41875094c20076e091 (patch)
tree21b2a60589d1c509e0c2386a1ebc8385a6e8349d /src/base/cp_annotate.hh
parentd5ef9ee06b4e8be52069b46a65af3a0a7e0a9817 (diff)
downloadgem5-6fd4bc34a154601ba0a74e41875094c20076e091.tar.xz
CPA: Add new object for gathering critical path annotations.
Diffstat (limited to 'src/base/cp_annotate.hh')
-rw-r--r--src/base/cp_annotate.hh522
1 files changed, 522 insertions, 0 deletions
diff --git a/src/base/cp_annotate.hh b/src/base/cp_annotate.hh
new file mode 100644
index 000000000..9ec39b6cb
--- /dev/null
+++ b/src/base/cp_annotate.hh
@@ -0,0 +1,522 @@
+/*
+ * Copyright (c) 2006-2009 The Regents of The University of Michigan
+ * 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.
+ *
+ * Authors: Ali Saidi
+ */
+
+#ifndef __BASE__CP_ANNOTATE_HH__
+#define __BASE__CP_ANNOTATE_HH__
+
+#include "base/loader/symtab.hh"
+#include "config/cp_annotate.hh"
+#include "sim/host.hh"
+#include "sim/serialize.hh"
+#include "sim/startup.hh"
+#include "sim/system.hh"
+
+#include <string>
+#include <list>
+#include <vector>
+#include <map>
+#include "base/hashmap.hh"
+#include "base/trace.hh"
+#if CP_ANNOTATE
+#include "params/CPA.hh"
+#endif
+
+class System;
+class ThreadContext;
+
+
+#if !CP_ANNOTATE
+class CPA : SimObject
+{
+ public:
+ enum flags {
+ FL_NONE = 0x00,
+ FL_HW = 0x01,
+ FL_BAD = 0x02,
+ FL_QOPP = 0x04,
+ FL_WAIT = 0x08,
+ FL_LINK = 0x10,
+ FL_RESET = 0x20
+ };
+
+ static CPA *cpa() { return NULL; }
+ static bool available() { return false; }
+ bool enabled() { return false; }
+ void swSmBegin(ThreadContext *tc) { return; }
+ void swSmEnd(ThreadContext *tc) { return; }
+ void swExplictBegin(ThreadContext *tc) { return; }
+ void swAutoBegin(ThreadContext *tc, Addr next_pc) { return; }
+ void swEnd(ThreadContext *tc) { return; }
+ void swQ(ThreadContext *tc) { return; }
+ void swDq(ThreadContext *tc) { return; }
+ void swPq(ThreadContext *tc) { return; }
+ void swRq(ThreadContext *tc) { return; }
+ void swWf(ThreadContext *tc) { return; }
+ void swWe(ThreadContext *tc) { return; }
+ void swSq(ThreadContext *tc) { return; }
+ void swAq(ThreadContext *tc) { return; }
+ void swLink(ThreadContext *tc) { return; }
+ void swIdentify(ThreadContext *tc) { return; }
+ uint64_t swGetId(ThreadContext *tc) { return 0; }
+ void swSyscallLink(ThreadContext *tc) { return; }
+ void hwBegin(flags f, System *sys, uint64_t frame, std::string sm,
+ std::string st) { return; }
+ void hwQ(flags f, System *sys, uint64_t frame, std::string sm,
+ std::string q, uint64_t qid, System *q_sys = NULL,
+ int32_t count = 1) { return; }
+ void hwDq(flags f, System *sys, uint64_t frame, std::string sm,
+ std::string q, uint64_t qid, System *q_sys = NULL,
+ int32_t count = 1) { return; }
+ void hwPq(flags f, System *sys, uint64_t frame, std::string sm,
+ std::string q, uint64_t qid, System *q_sys = NULL,
+ int32_t count = 1) { return; }
+ void hwRq(flags f, System *sys, uint64_t frame, std::string sm,
+ std::string q, uint64_t qid, System *q_sys = NULL,
+ int32_t count = 1) { return; }
+ void hwWf(flags f, System *sys, uint64_t frame, std::string sm,
+ std::string q, uint64_t qid, System *q_sys = NULL,
+ int32_t count = 1) { return; }
+ void hwWe(flags f, System *sys, uint64_t frame, std::string sm,
+ std::string q, uint64_t qid, System *q_sys = NULL,
+ int32_t count = 1) { return; }
+};
+#else
+class CPA : SimObject
+{
+ public:
+ typedef CPAParams Params;
+
+ /** The known operations that are written to the annotation output file. */
+ enum ops {
+ OP_BEGIN = 0x01,
+ OP_WAIT_EMPTY = 0x02,
+ OP_WAIT_FULL = 0x03,
+ OP_QUEUE = 0x04,
+ OP_DEQUEUE = 0x05,
+ OP_SIZE_QUEUE = 0x08,
+ OP_PEEK = 0x09,
+ OP_LINK = 0x0A,
+ OP_IDENT = 0x0B,
+ OP_RESERVE = 0x0C
+ };
+
+ /** Flags for the various options.*/
+ enum flags {
+ /* no flags */
+ FL_NONE = 0x00,
+ /* operation was done on hardware */
+ FL_HW = 0x01,
+ /* operation should cause a warning when encountered */
+ FL_BAD = 0x02,
+ /* Queue like a stack, not a queue */
+ FL_QOPP = 0x04,
+ /* Mark HW state as waiting for some non-resource constraint
+ * (e.g. wait because SM only starts after 10 items are queued) */
+ FL_WAIT = 0x08,
+ /* operation is linking to another state machine */
+ FL_LINK = 0x10,
+ /* queue should be completely cleared/reset before executing this
+ * operation */
+ FL_RESET = 0x20
+ };
+
+
+
+ protected:
+ const Params *
+ params() const
+ {
+ return dynamic_cast<const Params *>(_params);
+ }
+
+ /* struct that is written to the annotation output file */
+ struct AnnotateData : public RefCounted {
+
+ Tick time;
+ uint32_t data;
+ uint32_t orig_data;
+ uint16_t sm;
+ uint16_t stq;
+ uint8_t op;
+ uint8_t flag;
+ uint8_t cpu;
+ bool dump;
+
+ void serialize(std::ostream &os);
+ void unserialize(Checkpoint *cp, const std::string &section);
+
+ };
+
+ typedef RefCountingPtr<AnnotateData> AnnDataPtr;
+
+ /* header for the annotation file */
+ struct AnnotateHeader {
+ uint64_t version;
+ uint64_t num_recs;
+ uint64_t key_off;
+ uint64_t idx_off;
+ uint32_t key_len;
+ uint32_t idx_len;
+ };
+
+ AnnotateHeader ah;
+
+ std::vector<uint64_t> annotateIdx;
+
+ // number of state machines encountered in the simulation
+ int numSm;
+ // number of states encountered in the simulation
+ int numSmt;
+ // number of states/queues for a given state machine/system respectively
+ std::vector<int> numSt, numQ;
+ // number of systems in the simulation
+ int numSys;
+ // number of queues in the state machine
+ int numQs;
+ // maximum connection id assigned so far
+ uint64_t conId;
+
+ // Convert state strings into state ids
+ typedef m5::hash_map<std::string, int> SCache;
+ typedef std::vector<SCache> StCache;
+
+ // Convert sm and queue name,id into queue id
+ typedef std::pair<std::string, uint64_t> Id;
+ typedef m5::hash_map<Id, int> IdHCache;
+ typedef std::vector<IdHCache> IdCache;
+
+ // Hold mapping of sm and queues to output python
+ typedef std::vector<std::pair<int, Id> > IdMap;
+
+ // System pointer to name,id
+ typedef std::map<System*, std::pair<std::string, int> > NameCache;
+
+ // array of systems each of which is a stack of running sm
+ typedef std::pair<int, uint64_t> StackId;
+ typedef std::map<StackId, std::vector<int> > SmStack;
+
+ // map of each context and if it's currently in explict state mode
+ // states are not automatically updated until it leaves
+ typedef std::map<StackId, bool> SwExpl;
+
+ typedef std::map<int,int> IMap;
+ // List of annotate records have not been written/completed yet
+ typedef std::list<AnnDataPtr> AnnotateList;
+
+ // Maintain link state information
+ typedef std::map<int, int> LinkMap;
+
+ // SC Links
+ typedef m5::hash_map<Id, AnnDataPtr> ScHCache;
+ typedef std::vector<ScHCache> ScCache;
+
+
+ AnnotateList data;
+
+ // vector indexed by queueid to find current number of elements and bytes
+ std::vector<int> qSize;
+ std::vector<int32_t> qBytes;
+
+
+ // Turn state machine string into state machine id (small int)
+ // Used for outputting key to convert id back into string
+ SCache smtCache;
+ // Turn state machine id, state name into state id (small int)
+ StCache stCache;
+ // turn system, queue, and queue identify into qid (small int)
+ // turn system, state, and context into state machine id (small int)
+ IdCache qCache, smCache;
+ //Link state machines accross system calls
+ ScCache scLinks;
+ // System pointer to name,id
+ NameCache nameCache;
+ // Stack of state machines currently nested (should unwind correctly)
+ SmStack smStack;
+ // Map of currently outstanding links
+ LinkMap lnMap;
+ // If the state machine is currently exculding automatic changes
+ SwExpl swExpl;
+ // Last state that a given state machine was in
+ IMap lastState;
+ // Hold mapping of sm and queues to output python
+ IdMap smMap, qMap;
+ // Items still in queue, used for sanity checking
+ std::vector<AnnotateList> qData;
+
+ void doDq(System *sys, int flags, int cpu, int sm, std::string q, int qi,
+ int count);
+ void doQ(System *sys, int flags, int cpu, int sm, std::string q, int qi,
+ int count);
+
+ void doSwSmEnd(System *sys, int cpuid, std::string sm, uint64_t frame);
+
+ // Turn a system id, state machine string, state machine id into a small int
+ // for annotation output
+ int
+ getSm(int sysi, std::string si, uint64_t id)
+ {
+ int smi;
+ Id smid = Id(si, id);
+
+ smi = smCache[sysi-1][smid];
+ if (smi == 0) {
+ smCache[sysi-1][smid] = smi = ++numSm;
+ assert(smi < 65535);
+ smMap.push_back(std::make_pair<int, Id>(sysi, smid));
+ }
+ return smi;
+ }
+
+ // Turn a state machine string, state string into a small int
+ // for annotation output
+ int
+ getSt(std::string sm, std::string s)
+ {
+ int sti, smi;
+
+ smi = smtCache[sm];
+ if (smi == 0)
+ smi = smtCache[sm] = ++numSmt;
+
+ while (stCache.size() < smi) {
+ //stCache.resize(sm);
+ stCache.push_back(SCache());
+ numSt.push_back(0);
+ }
+ //assert(stCache.size() == sm);
+ //assert(numSt.size() == sm);
+ sti = stCache[smi-1][s];
+ if (sti == 0)
+ stCache[smi-1][s] = sti = ++numSt[smi-1];
+ return sti;
+ }
+
+ // Turn state machine pointer into a smal int for annotation output
+ int
+ getSys(System *s)
+ {
+ NameCache::iterator i = nameCache.find(s);
+ if (i == nameCache.end()) {
+ nameCache[s] = std::make_pair<std::string,int>(s->name(), ++numSys);
+ i = nameCache.find(s);
+ // might need to put smstackid into map here, but perhaps not
+ //smStack.push_back(std::vector<int>());
+ //swExpl.push_back(false);
+ numQ.push_back(0);
+ qCache.push_back(IdHCache());
+ smCache.push_back(IdHCache());
+ scLinks.push_back(ScHCache());
+ }
+ return i->second.second;
+ }
+
+ // Turn queue name, and queue context into small int for
+ // annotation output
+ int
+ getQ(int sys, std::string q, uint64_t id)
+ {
+ int qi;
+ Id qid = Id(q, id);
+
+ qi = qCache[sys-1][qid];
+ if (qi == 0) {
+ qi = qCache[sys-1][qid] = ++numQs;
+ assert(qi < 65535);
+ qSize.push_back(0);
+ qBytes.push_back(0);
+ qData.push_back(AnnotateList());
+ numQ[sys-1]++;
+ qMap.push_back(std::make_pair<int, Id>(sys, qid));
+ }
+ return qi;
+ }
+
+ void swBegin(System *sys, int cpuid, std::string st, uint64_t frame,
+ bool expl = false, int flags = FL_NONE);
+
+ AnnDataPtr add(int t, int f, int c, int sm, int stq, int32_t data=0);
+
+ std::ostream *osbin;
+
+ bool _enabled;
+
+ /** Only allow one CPA object in a system. It doesn't make sense to have
+ * more that one per simulation because if a part of the system was
+ * important it would have annotations and queues, and with more than one
+ * object none of the sanity checking for queues will work. */
+ static bool exists;
+ static CPA *_cpa;
+
+
+ std::map<std::string, SymbolTable*> userApp;
+
+ public:
+ static CPA *cpa() { return _cpa; }
+ void swSmBegin(ThreadContext *tc);
+ void swSmEnd(ThreadContext *tc);
+ void swExplictBegin(ThreadContext *tc);
+ void swAutoBegin(ThreadContext *tc, Addr next_pc);
+ void swEnd(ThreadContext *tc);
+ void swQ(ThreadContext *tc);
+ void swDq(ThreadContext *tc);
+ void swPq(ThreadContext *tc);
+ void swRq(ThreadContext *tc);
+ void swWf(ThreadContext *tc);
+ void swWe(ThreadContext *tc);
+ void swSq(ThreadContext *tc);
+ void swAq(ThreadContext *tc);
+ void swLink(ThreadContext *tc);
+ void swIdentify(ThreadContext *tc);
+ uint64_t swGetId(ThreadContext *tc);
+ void swSyscallLink(ThreadContext *tc);
+
+ inline void hwBegin(flags f, System *sys, uint64_t frame, std::string sm,
+ std::string st)
+ {
+ if (!enabled())
+ return;
+
+ int sysi = getSys(sys);
+ int smi = getSm(sysi, sm, frame);
+ add(OP_BEGIN, FL_HW | f, 0, smi, getSt(sm, st));
+ if (f & FL_BAD)
+ warn("BAD state encountered: at cycle %d: %s\n", curTick, st);
+ }
+
+ inline void hwQ(flags f, System *sys, uint64_t frame, std::string sm,
+ std::string q, uint64_t qid, System *q_sys = NULL, int32_t count = 1)
+ {
+ if (!enabled())
+ return;
+
+ int sysi = getSys(sys);
+ int qi = getQ(q_sys ? getSys(q_sys) : sysi, q, qid);
+ DPRINTFS(AnnotateQ, sys,
+ "hwQ: %s[%#x] cur size %d %d bytes: %d adding: %d\n",
+ q, qid, qSize[qi-1], qData[qi-1].size(), qBytes[qi-1], count);
+ doQ(sys, FL_HW | f, 0, getSm(sysi, sm, frame), q, qi, count);
+
+ }
+
+ inline void hwDq(flags f, System *sys, uint64_t frame, std::string sm,
+ std::string q, uint64_t qid, System *q_sys = NULL, int32_t count = 1)
+ {
+ if (!enabled())
+ return;
+
+ int sysi = getSys(sys);
+ int qi = getQ(q_sys ? getSys(q_sys) : sysi, q, qid);
+ DPRINTFS(AnnotateQ, sys,
+ "hwDQ: %s[%#x] cur size %d %d bytes: %d removing: %d\n",
+ q, qid, qSize[qi-1], qData[qi-1].size(), qBytes[qi-1], count);
+ doDq(sys, FL_HW | f, 0, getSm(sysi,sm, frame), q, qi, count);
+ }
+
+ inline void hwPq(flags f, System *sys, uint64_t frame, std::string sm,
+ std::string q, uint64_t qid, System *q_sys = NULL, int32_t count = 1)
+ {
+ if (!enabled())
+ return;
+
+ int sysi = getSys(sys);
+ int qi = getQ(q_sys ? getSys(q_sys) : sysi, q, qid);
+ DPRINTFS(AnnotateQ, sys,
+ "hwPQ: %s[%#x] cur size %d %d bytes: %d peeking: %d\n",
+ q, qid, qSize[qi-1], qData[qi-1].size(), qBytes[qi-1], count);
+ add(OP_PEEK, FL_HW | f, 0, getSm(sysi, sm, frame), qi, count);
+ }
+
+ inline void hwRq(flags f, System *sys, uint64_t frame, std::string sm,
+ std::string q, uint64_t qid, System *q_sys = NULL, int32_t count = 1)
+ {
+ if (!enabled())
+ return;
+
+ int sysi = getSys(sys);
+ int qi = getQ(q_sys ? getSys(q_sys) : sysi, q, qid);
+ DPRINTFS(AnnotateQ, sys,
+ "hwRQ: %s[%#x] cur size %d %d bytes: %d reserving: %d\n",
+ q, qid, qSize[qi-1], qData[qi-1].size(), qBytes[qi-1], count);
+ add(OP_RESERVE, FL_HW | f, 0, getSm(sysi, sm, frame), qi, count);
+ }
+
+ inline void hwWf(flags f, System *sys, uint64_t frame, std::string sm,
+ std::string q, uint64_t qid, System *q_sys = NULL, int32_t count = 1)
+ {
+ if (!enabled())
+ return;
+
+ int sysi = getSys(sys);
+ int qi = getQ(q_sys ? getSys(q_sys) : sysi, q, qid);
+ add(OP_WAIT_FULL, FL_HW | f, 0, getSm(sysi, sm, frame), qi, count);
+ }
+
+ inline void hwWe(flags f, System *sys, uint64_t frame, std::string sm,
+ std::string q, uint64_t qid, System *q_sys = NULL, int32_t count = 1)
+ {
+ if (!enabled())
+ return;
+
+ int sysi = getSys(sys);
+ int qi = getQ(q_sys ? getSys(q_sys) : sysi, q, qid);
+ add(OP_WAIT_EMPTY, FL_HW | f, 0, getSm(sysi, sm, frame), qi, count);
+ }
+
+ public:
+ CPA(Params *p);
+ void startup();
+
+ // This code is ISA specific and will need to be changed
+ // if the annotation code is used for something other than Alpha
+ inline uint64_t getFrame(ThreadContext *tc)
+ { return (tc->readMiscRegNoEffect(TheISA::IPR_PALtemp23) &
+ ~ULL(0x3FFF)); }
+
+ static bool available() { return true; }
+
+ bool
+ enabled()
+ {
+ if (!this)
+ return false;
+ return _enabled;
+ }
+
+ void dump(bool all);
+ void dumpKey();
+
+ void serialize(std::ostream &os);
+ void unserialize(Checkpoint *cp, const std::string &section);
+
+};
+#endif // !CP_ANNOTATE
+
+#endif //__BASE__CP_ANNOTATE_HH__
+