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