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