cp_annotate.hh revision 6658
16145SN/A/*
26386SN/A * Copyright (c) 2006-2009 The Regents of The University of Michigan
36386SN/A * All rights reserved.
46386SN/A *
56386SN/A * Redistribution and use in source and binary forms, with or without
66386SN/A * modification, are permitted provided that the following conditions are
76386SN/A * met: redistributions of source code must retain the above copyright
86386SN/A * notice, this list of conditions and the following disclaimer;
96386SN/A * redistributions in binary form must reproduce the above copyright
106386SN/A * notice, this list of conditions and the following disclaimer in the
116386SN/A * documentation and/or other materials provided with the distribution;
126386SN/A * neither the name of the copyright holders nor the names of its
136386SN/A * contributors may be used to endorse or promote products derived from
146386SN/A * this software without specific prior written permission.
156386SN/A *
166386SN/A * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
176386SN/A * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
186386SN/A * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
196386SN/A * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
206386SN/A * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
216386SN/A * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
226386SN/A * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
236386SN/A * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
246386SN/A * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
256386SN/A * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
266386SN/A * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
276386SN/A *
286145SN/A * Authors: Ali Saidi
297553SN/A */
307553SN/A
317553SN/A#ifndef __BASE__CP_ANNOTATE_HH__
327553SN/A#define __BASE__CP_ANNOTATE_HH__
337553SN/A
346145SN/A#include <string>
357553SN/A#include <list>
367553SN/A#include <vector>
376145SN/A#include <map>
388229Snate@binkert.org
397632SBrad.Beckmann@amd.com#include "base/hashmap.hh"
407553SN/A#include "base/loader/symtab.hh"
417553SN/A#include "base/trace.hh"
426145SN/A#include "base/types.hh"
437553SN/A#include "config/cp_annotate.hh"
447553SN/A#include "config/the_isa.hh"
457553SN/A#include "sim/serialize.hh"
467553SN/A#include "sim/startup.hh"
477553SN/A#include "sim/system.hh"
487553SN/A
497553SN/A#if CP_ANNOTATE
507553SN/A#include "params/CPA.hh"
517553SN/A#endif
528655Sandreas.hansson@arm.com
537553SN/Aclass System;
547553SN/Aclass ThreadContext;
557553SN/A
567553SN/A
578655Sandreas.hansson@arm.com#if !CP_ANNOTATE
588655Sandreas.hansson@arm.comclass CPA
598655Sandreas.hansson@arm.com{
606145SN/A  public:
616145SN/A    enum flags {
627553SN/A        FL_NONE     = 0x00,
636145SN/A        FL_HW       = 0x01,
64        FL_BAD      = 0x02,
65        FL_QOPP     = 0x04,
66        FL_WAIT     = 0x08,
67        FL_LINK     = 0x10,
68        FL_RESET    = 0x20
69    };
70
71    static CPA *cpa()                                        { return NULL; }
72    static bool available()                                 { return false; }
73    bool enabled()                                          { return false; }
74    void swSmBegin(ThreadContext *tc)                             { return; }
75    void swSmEnd(ThreadContext *tc)                               { return; }
76    void swExplictBegin(ThreadContext *tc)                        { return; }
77    void swAutoBegin(ThreadContext *tc, Addr next_pc)             { return; }
78    void swEnd(ThreadContext *tc)                                 { return; }
79    void swQ(ThreadContext *tc)                                   { return; }
80    void swDq(ThreadContext *tc)                                  { return; }
81    void swPq(ThreadContext *tc)                                  { return; }
82    void swRq(ThreadContext *tc)                                  { return; }
83    void swWf(ThreadContext *tc)                                  { return; }
84    void swWe(ThreadContext *tc)                                  { return; }
85    void swSq(ThreadContext *tc)                                  { return; }
86    void swAq(ThreadContext *tc)                                  { return; }
87    void swLink(ThreadContext *tc)                                { return; }
88    void swIdentify(ThreadContext *tc)                            { return; }
89    uint64_t swGetId(ThreadContext *tc)                         { return 0; }
90    void swSyscallLink(ThreadContext *tc)                         { return; }
91    void hwBegin(flags f, System *sys, uint64_t frame, std::string sm,
92                 std::string st)                                  { return; }
93    void hwQ(flags f, System *sys, uint64_t frame, std::string sm,
94             std::string q, uint64_t qid, System *q_sys = NULL,
95             int32_t count = 1)                                   { return; }
96    void hwDq(flags f, System *sys, uint64_t frame, std::string sm,
97              std::string q, uint64_t qid, System *q_sys = NULL,
98              int32_t count = 1)                                  { return; }
99    void hwPq(flags f, System *sys, uint64_t frame, std::string sm,
100              std::string q, uint64_t qid, System *q_sys = NULL,
101              int32_t count = 1)                                  { return; }
102    void hwRq(flags f, System *sys, uint64_t frame, std::string sm,
103              std::string q, uint64_t qid, System *q_sys = NULL,
104              int32_t count = 1)                                  { return; }
105    void hwWf(flags f, System *sys, uint64_t frame, std::string sm,
106              std::string q, uint64_t qid, System *q_sys = NULL,
107              int32_t count = 1)                                  { return; }
108    void hwWe(flags f, System *sys, uint64_t frame, std::string sm,
109              std::string q, uint64_t qid, System *q_sys = NULL,
110              int32_t count = 1)                                  { return; }
111};
112#else
113class CPA : SimObject
114{
115  public:
116    typedef CPAParams Params;
117
118    /** The known operations that are written to the annotation output file. */
119    enum ops {
120        OP_BEGIN           = 0x01,
121        OP_WAIT_EMPTY      = 0x02,
122        OP_WAIT_FULL       = 0x03,
123        OP_QUEUE           = 0x04,
124        OP_DEQUEUE         = 0x05,
125        OP_SIZE_QUEUE      = 0x08,
126        OP_PEEK            = 0x09,
127        OP_LINK            = 0x0A,
128        OP_IDENT           = 0x0B,
129        OP_RESERVE         = 0x0C
130    };
131
132    /** Flags for the various options.*/
133    enum flags {
134        /* no flags */
135        FL_NONE     = 0x00,
136        /* operation was done on hardware */
137        FL_HW       = 0x01,
138        /* operation should cause a warning when encountered */
139        FL_BAD      = 0x02,
140        /* Queue like a stack, not a queue */
141        FL_QOPP     = 0x04,
142        /* Mark HW state as waiting for some non-resource constraint
143         * (e.g. wait because SM only starts after 10 items are queued) */
144        FL_WAIT     = 0x08,
145        /* operation is linking to another state machine */
146        FL_LINK     = 0x10,
147        /* queue should be completely cleared/reset before executing this
148         * operation */
149        FL_RESET    = 0x20
150    };
151
152
153
154  protected:
155    const Params *
156        params() const
157        {
158            return dynamic_cast<const Params *>(_params);
159        }
160
161    /* struct that is written to the annotation output file */
162    struct AnnotateData : public RefCounted {
163
164        Tick time;
165        uint32_t data;
166        uint32_t orig_data;
167        uint16_t sm;
168        uint16_t stq;
169        uint8_t  op;
170        uint8_t  flag;
171        uint8_t  cpu;
172        bool dump;
173
174        void serialize(std::ostream &os);
175        void unserialize(Checkpoint *cp, const std::string &section);
176
177    };
178
179    typedef RefCountingPtr<AnnotateData> AnnDataPtr;
180
181    /* header for the annotation file */
182    struct AnnotateHeader {
183        uint64_t version;
184        uint64_t num_recs;
185        uint64_t key_off;
186        uint64_t idx_off;
187        uint32_t key_len;
188        uint32_t idx_len;
189    };
190
191    AnnotateHeader ah;
192
193    std::vector<uint64_t> annotateIdx;
194
195    // number of state machines encountered in the simulation
196    int numSm;
197    // number of states encountered in the simulation
198    int numSmt;
199    // number of states/queues for a given state machine/system respectively
200    std::vector<int> numSt, numQ;
201    // number of systems in the simulation
202    int numSys;
203    // number of queues in the state machine
204    int numQs;
205    // maximum connection id assigned so far
206    uint64_t conId;
207
208    // Convert state strings into state ids
209    typedef m5::hash_map<std::string, int> SCache;
210    typedef std::vector<SCache> StCache;
211
212    // Convert sm and queue name,id into queue id
213    typedef std::pair<std::string, uint64_t> Id;
214    typedef m5::hash_map<Id, int> IdHCache;
215    typedef std::vector<IdHCache> IdCache;
216
217    // Hold mapping of sm and queues to output python
218    typedef std::vector<std::pair<int, Id> > IdMap;
219
220    // System pointer to name,id
221    typedef std::map<System*, std::pair<std::string, int> > NameCache;
222
223    // array of systems each of which is a stack of running sm
224    typedef std::pair<int, uint64_t> StackId;
225    typedef std::map<StackId, std::vector<int> > SmStack;
226
227    // map of each context and if it's currently in explict state mode
228    // states are not automatically updated until it leaves
229    typedef std::map<StackId, bool> SwExpl;
230
231    typedef std::map<int,int> IMap;
232    // List of annotate records have not been written/completed yet
233    typedef std::list<AnnDataPtr> AnnotateList;
234
235    // Maintain link state information
236    typedef std::map<int, int> LinkMap;
237
238    // SC Links
239    typedef m5::hash_map<Id, AnnDataPtr> ScHCache;
240    typedef std::vector<ScHCache> ScCache;
241
242
243    AnnotateList data;
244
245    // vector indexed by queueid to find current number of elements and bytes
246    std::vector<int> qSize;
247    std::vector<int32_t> qBytes;
248
249
250    // Turn state machine string into state machine id (small int)
251    // Used for outputting key to convert id back into string
252    SCache smtCache;
253    // Turn state machine id, state name into state id (small int)
254    StCache stCache;
255    // turn system, queue, and queue identify into qid (small int)
256    // turn system, state, and context into state machine id (small int)
257    IdCache qCache, smCache;
258    //Link state machines accross system calls
259    ScCache scLinks;
260    // System pointer to name,id
261    NameCache nameCache;
262    // Stack of state machines currently nested (should unwind correctly)
263    SmStack smStack;
264    // Map of currently outstanding links
265    LinkMap lnMap;
266    // If the state machine is currently exculding automatic changes
267    SwExpl swExpl;
268    // Last state that a given state machine was in
269    IMap lastState;
270    // Hold mapping of sm and queues to output python
271    IdMap smMap, qMap;
272    // Items still in queue, used for sanity checking
273    std::vector<AnnotateList> qData;
274
275    void doDq(System *sys, int flags, int cpu, int sm, std::string q, int qi,
276            int count);
277    void doQ(System *sys, int flags, int cpu, int sm, std::string q, int qi,
278            int count);
279
280    void doSwSmEnd(System *sys, int cpuid, std::string sm, uint64_t frame);
281
282    // Turn a system id, state machine string, state machine id into a small int
283    // for annotation output
284    int
285    getSm(int sysi, std::string si, uint64_t id)
286    {
287        int smi;
288        Id smid = Id(si, id);
289
290        smi = smCache[sysi-1][smid];
291        if (smi == 0) {
292            smCache[sysi-1][smid] = smi = ++numSm;
293            assert(smi < 65535);
294            smMap.push_back(std::make_pair<int, Id>(sysi, smid));
295        }
296        return smi;
297    }
298
299    // Turn a state machine string, state string into a small int
300    // for annotation output
301    int
302    getSt(std::string sm, std::string s)
303    {
304        int sti, smi;
305
306        smi = smtCache[sm];
307        if (smi == 0)
308           smi = smtCache[sm] = ++numSmt;
309
310        while (stCache.size() < smi) {
311            //stCache.resize(sm);
312            stCache.push_back(SCache());
313            numSt.push_back(0);
314        }
315        //assert(stCache.size() == sm);
316        //assert(numSt.size() == sm);
317        sti = stCache[smi-1][s];
318        if (sti == 0)
319            stCache[smi-1][s] = sti = ++numSt[smi-1];
320        return sti;
321    }
322
323    // Turn state machine pointer into a smal int for annotation output
324    int
325    getSys(System *s)
326    {
327        NameCache::iterator i = nameCache.find(s);
328        if (i == nameCache.end()) {
329            nameCache[s] = std::make_pair<std::string,int>(s->name(), ++numSys);
330            i = nameCache.find(s);
331            // might need to put smstackid into map here, but perhaps not
332            //smStack.push_back(std::vector<int>());
333            //swExpl.push_back(false);
334            numQ.push_back(0);
335            qCache.push_back(IdHCache());
336            smCache.push_back(IdHCache());
337            scLinks.push_back(ScHCache());
338        }
339        return i->second.second;
340    }
341
342    // Turn queue name, and queue context into small int for
343    // annotation output
344    int
345    getQ(int sys, std::string q, uint64_t id)
346    {
347        int qi;
348        Id qid = Id(q, id);
349
350        qi = qCache[sys-1][qid];
351        if (qi == 0) {
352            qi = qCache[sys-1][qid] = ++numQs;
353            assert(qi < 65535);
354            qSize.push_back(0);
355            qBytes.push_back(0);
356            qData.push_back(AnnotateList());
357            numQ[sys-1]++;
358            qMap.push_back(std::make_pair<int, Id>(sys, qid));
359        }
360        return qi;
361    }
362
363    void swBegin(System *sys, int cpuid, std::string st, uint64_t frame,
364            bool expl = false, int flags = FL_NONE);
365
366    AnnDataPtr add(int t, int f, int c, int sm, int stq, int32_t data=0);
367
368    std::ostream *osbin;
369
370    bool _enabled;
371
372    /** Only allow one CPA object in a system. It doesn't make sense to have
373     * more that one per simulation because if a part of the system was
374     * important it would have annotations and queues, and with more than one
375     * object none of the sanity checking for queues will work. */
376    static bool exists;
377    static CPA *_cpa;
378
379
380    std::map<std::string, SymbolTable*> userApp;
381
382  public:
383    static CPA *cpa() { return _cpa; }
384    void swSmBegin(ThreadContext *tc);
385    void swSmEnd(ThreadContext *tc);
386    void swExplictBegin(ThreadContext *tc);
387    void swAutoBegin(ThreadContext *tc, Addr next_pc);
388    void swEnd(ThreadContext *tc);
389    void swQ(ThreadContext *tc);
390    void swDq(ThreadContext *tc);
391    void swPq(ThreadContext *tc);
392    void swRq(ThreadContext *tc);
393    void swWf(ThreadContext *tc);
394    void swWe(ThreadContext *tc);
395    void swSq(ThreadContext *tc);
396    void swAq(ThreadContext *tc);
397    void swLink(ThreadContext *tc);
398    void swIdentify(ThreadContext *tc);
399    uint64_t swGetId(ThreadContext *tc);
400    void swSyscallLink(ThreadContext *tc);
401
402    inline void hwBegin(flags f, System *sys, uint64_t frame, std::string sm,
403            std::string st)
404    {
405        if (!enabled())
406            return;
407
408        int sysi = getSys(sys);
409        int smi = getSm(sysi, sm, frame);
410        add(OP_BEGIN, FL_HW | f, 0, smi, getSt(sm, st));
411        if (f & FL_BAD)
412            warn("BAD state encountered: at cycle %d: %s\n", curTick, st);
413    }
414
415    inline void hwQ(flags f, System *sys, uint64_t frame, std::string sm,
416            std::string q, uint64_t qid, System *q_sys = NULL, int32_t count = 1)
417    {
418        if (!enabled())
419            return;
420
421        int sysi = getSys(sys);
422        int qi = getQ(q_sys ?  getSys(q_sys) : sysi, q, qid);
423        DPRINTFS(AnnotateQ, sys,
424                "hwQ: %s[%#x] cur size %d %d bytes: %d adding: %d\n",
425                q, qid, qSize[qi-1], qData[qi-1].size(), qBytes[qi-1], count);
426        doQ(sys, FL_HW | f, 0, getSm(sysi, sm, frame), q, qi, count);
427
428    }
429
430    inline void hwDq(flags f, System *sys, uint64_t frame, std::string sm,
431            std::string q, uint64_t qid, System *q_sys = NULL, int32_t count = 1)
432    {
433        if (!enabled())
434            return;
435
436        int sysi = getSys(sys);
437        int qi = getQ(q_sys ?  getSys(q_sys) : sysi, q, qid);
438        DPRINTFS(AnnotateQ, sys,
439                "hwDQ: %s[%#x] cur size %d %d bytes: %d removing: %d\n",
440                q, qid, qSize[qi-1], qData[qi-1].size(), qBytes[qi-1], count);
441        doDq(sys, FL_HW | f, 0, getSm(sysi,sm, frame), q, qi, count);
442    }
443
444    inline void hwPq(flags f, System *sys, uint64_t frame, std::string sm,
445            std::string q, uint64_t qid, System *q_sys = NULL, int32_t count = 1)
446    {
447        if (!enabled())
448            return;
449
450        int sysi = getSys(sys);
451        int qi = getQ(q_sys ?  getSys(q_sys) : sysi, q, qid);
452        DPRINTFS(AnnotateQ, sys,
453                "hwPQ: %s[%#x] cur size %d %d bytes: %d peeking: %d\n",
454                q, qid, qSize[qi-1], qData[qi-1].size(), qBytes[qi-1], count);
455        add(OP_PEEK, FL_HW | f, 0, getSm(sysi, sm, frame), qi, count);
456    }
457
458    inline void hwRq(flags f, System *sys, uint64_t frame, std::string sm,
459            std::string q, uint64_t qid, System *q_sys = NULL, int32_t count = 1)
460    {
461        if (!enabled())
462            return;
463
464        int sysi = getSys(sys);
465        int qi = getQ(q_sys ?  getSys(q_sys) : sysi, q, qid);
466        DPRINTFS(AnnotateQ, sys,
467                "hwRQ: %s[%#x] cur size %d %d bytes: %d reserving: %d\n",
468                q, qid, qSize[qi-1], qData[qi-1].size(), qBytes[qi-1], count);
469        add(OP_RESERVE, FL_HW | f, 0, getSm(sysi, sm, frame), qi, count);
470    }
471
472    inline void hwWf(flags f, System *sys, uint64_t frame, std::string sm,
473            std::string q, uint64_t qid, System *q_sys = NULL, int32_t count = 1)
474    {
475        if (!enabled())
476            return;
477
478        int sysi = getSys(sys);
479        int qi = getQ(q_sys ?  getSys(q_sys) : sysi, q, qid);
480        add(OP_WAIT_FULL, FL_HW | f, 0, getSm(sysi, sm, frame), qi, count);
481    }
482
483    inline void hwWe(flags f, System *sys, uint64_t frame, std::string sm,
484            std::string q, uint64_t qid, System *q_sys = NULL, int32_t count = 1)
485    {
486        if (!enabled())
487            return;
488
489        int sysi = getSys(sys);
490        int qi = getQ(q_sys ?  getSys(q_sys) : sysi, q, qid);
491        add(OP_WAIT_EMPTY, FL_HW | f, 0, getSm(sysi, sm, frame), qi, count);
492    }
493
494  public:
495    CPA(Params *p);
496    void startup();
497
498    // This code is ISA specific and will need to be changed
499    // if the annotation code is used for something other than Alpha
500    inline uint64_t getFrame(ThreadContext *tc)
501        { return (tc->readMiscRegNoEffect(TheISA::IPR_PALtemp23) &
502                ~ULL(0x3FFF)); }
503
504    static bool available()  { return true; }
505
506    bool
507    enabled()
508    {
509        if (!this)
510            return false;
511        return _enabled;
512    }
513
514    void dump(bool all);
515    void dumpKey();
516
517    void serialize(std::ostream &os);
518    void unserialize(Checkpoint *cp, const std::string &section);
519
520};
521#endif // !CP_ANNOTATE
522
523#endif //__BASE__CP_ANNOTATE_HH__
524
525