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