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 * 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 <unordered_map> 51#include <vector> 52 53#include "base/loader/symtab.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 */ 130namespace std { 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} 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 : public Serializable { 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(CheckpointOut &cp) const override; 206 void unserialize(CheckpointIn &cp) override; 207 }; 208 209 typedef std::shared_ptr<AnnotateData> AnnDataPtr; 210 211 /* header for the annotation file */ 212 struct AnnotateHeader { 213 uint64_t version; 214 uint64_t num_recs; 215 uint64_t key_off; 216 uint64_t idx_off; 217 uint32_t key_len; 218 uint32_t idx_len; 219 }; 220 221 AnnotateHeader ah; 222 223 std::vector<uint64_t> annotateIdx; 224 225 // number of state machines encountered in the simulation 226 int numSm; 227 // number of states encountered in the simulation 228 int numSmt; 229 // number of states/queues for a given state machine/system respectively 230 std::vector<int> numSt, numQ; 231 // number of systems in the simulation 232 int numSys; 233 // number of queues in the state machine 234 int numQs; 235 // maximum connection id assigned so far 236 uint64_t conId; 237 238 // Convert state strings into state ids 239 typedef std::unordered_map<std::string, int> SCache; 240 typedef std::vector<SCache> StCache; 241 242 // Convert sm and queue name,id into queue id 243 typedef std::pair<std::string, uint64_t> Id; 244 typedef std::unordered_map<Id, int> IdHCache; 245 typedef std::vector<IdHCache> IdCache; 246 247 // Hold mapping of sm and queues to output python 248 typedef std::vector<std::pair<int, Id> > IdMap; 249 250 // System pointer to name,id 251 typedef std::map<System*, std::pair<std::string, int> > NameCache; 252 253 // array of systems each of which is a stack of running sm 254 typedef std::pair<int, uint64_t> StackId; 255 typedef std::map<StackId, std::vector<int> > SmStack; 256 257 // map of each context and if it's currently in explict state mode 258 // states are not automatically updated until it leaves 259 typedef std::map<StackId, bool> SwExpl; 260 261 typedef std::map<int,int> IMap; 262 // List of annotate records have not been written/completed yet 263 typedef std::list<AnnDataPtr> AnnotateList; 264 265 // Maintain link state information 266 typedef std::map<int, int> LinkMap; 267 268 // SC Links 269 typedef std::unordered_map<Id, AnnDataPtr> ScHCache; 270 typedef std::vector<ScHCache> ScCache; 271 272 273 AnnotateList data; 274 275 // vector indexed by queueid to find current number of elements and bytes 276 std::vector<int> qSize; 277 std::vector<int32_t> qBytes; 278 279 280 // Turn state machine string into state machine id (small int) 281 // Used for outputting key to convert id back into string 282 SCache smtCache; 283 // Turn state machine id, state name into state id (small int) 284 StCache stCache; 285 // turn system, queue, and queue identify into qid (small int) 286 // turn system, state, and context into state machine id (small int) 287 IdCache qCache, smCache; 288 //Link state machines accross system calls 289 ScCache scLinks; 290 // System pointer to name,id 291 NameCache nameCache; 292 // Stack of state machines currently nested (should unwind correctly) 293 SmStack smStack; 294 // Map of currently outstanding links 295 LinkMap lnMap; 296 // If the state machine is currently exculding automatic changes 297 SwExpl swExpl; 298 // Last state that a given state machine was in 299 IMap lastState; 300 // Hold mapping of sm and queues to output python 301 IdMap smMap, qMap; 302 // Items still in queue, used for sanity checking 303 std::vector<AnnotateList> qData; 304 305 void doDq(System *sys, int flags, int cpu, int sm, std::string q, int qi, 306 int count); 307 void doQ(System *sys, int flags, int cpu, int sm, std::string q, int qi, 308 int count); 309 310 void doSwSmEnd(System *sys, int cpuid, std::string sm, uint64_t frame); 311 312 // Turn a system id, state machine string, state machine id into a small int 313 // for annotation output 314 int 315 getSm(int sysi, std::string si, uint64_t id) 316 { 317 int smi; 318 Id smid = Id(si, id); 319 320 smi = smCache[sysi-1][smid]; 321 if (smi == 0) { 322 smCache[sysi-1][smid] = smi = ++numSm; 323 assert(smi < 65535); 324 smMap.push_back(std::make_pair(sysi, smid)); 325 } 326 return smi; 327 } 328 329 // Turn a state machine string, state string into a small int 330 // for annotation output 331 int 332 getSt(std::string sm, std::string s) 333 { 334 int sti, smi; 335 336 smi = smtCache[sm]; 337 if (smi == 0) 338 smi = smtCache[sm] = ++numSmt; 339 340 while (stCache.size() < smi) { 341 //stCache.resize(sm); 342 stCache.push_back(SCache()); 343 numSt.push_back(0); 344 } 345 //assert(stCache.size() == sm); 346 //assert(numSt.size() == sm); 347 sti = stCache[smi-1][s]; 348 if (sti == 0) 349 stCache[smi-1][s] = sti = ++numSt[smi-1]; 350 return sti; 351 } 352 353 // Turn state machine pointer into a smal int for annotation output 354 int 355 getSys(System *s) 356 { 357 NameCache::iterator i = nameCache.find(s); 358 if (i == nameCache.end()) { 359 nameCache[s] = std::make_pair(s->name(), ++numSys); 360 i = nameCache.find(s); 361 // might need to put smstackid into map here, but perhaps not 362 //smStack.push_back(std::vector<int>()); 363 //swExpl.push_back(false); 364 numQ.push_back(0); 365 qCache.push_back(IdHCache()); 366 smCache.push_back(IdHCache()); 367 scLinks.push_back(ScHCache()); 368 } 369 return i->second.second; 370 } 371 372 // Turn queue name, and queue context into small int for 373 // annotation output 374 int 375 getQ(int sys, std::string q, uint64_t id) 376 { 377 int qi; 378 Id qid = Id(q, id); 379 380 qi = qCache[sys-1][qid]; 381 if (qi == 0) { 382 qi = qCache[sys-1][qid] = ++numQs; 383 assert(qi < 65535); 384 qSize.push_back(0); 385 qBytes.push_back(0); 386 qData.push_back(AnnotateList()); 387 numQ[sys-1]++; 388 qMap.push_back(std::make_pair(sys, qid)); 389 } 390 return qi; 391 } 392 393 void swBegin(System *sys, int cpuid, std::string st, uint64_t frame, 394 bool expl = false, int flags = FL_NONE); 395 396 AnnDataPtr add(int t, int f, int c, int sm, int stq, int32_t data=0); 397 398 std::ostream *osbin; 399 400 bool _enabled; 401 402 /** Only allow one CPA object in a system. It doesn't make sense to have 403 * more that one per simulation because if a part of the system was 404 * important it would have annotations and queues, and with more than one 405 * object none of the sanity checking for queues will work. */ 406 static bool exists; 407 static CPA *_cpa; 408 409 410 std::map<std::string, SymbolTable*> userApp; 411 412 public: 413 static CPA *cpa() { return _cpa; } 414 void swSmBegin(ThreadContext *tc); 415 void swSmEnd(ThreadContext *tc); 416 void swExplictBegin(ThreadContext *tc); 417 void swAutoBegin(ThreadContext *tc, Addr next_pc); 418 void swEnd(ThreadContext *tc); 419 void swQ(ThreadContext *tc); 420 void swDq(ThreadContext *tc); 421 void swPq(ThreadContext *tc); 422 void swRq(ThreadContext *tc); 423 void swWf(ThreadContext *tc); 424 void swWe(ThreadContext *tc); 425 void swSq(ThreadContext *tc); 426 void swAq(ThreadContext *tc); 427 void swLink(ThreadContext *tc); 428 void swIdentify(ThreadContext *tc); 429 uint64_t swGetId(ThreadContext *tc); 430 void swSyscallLink(ThreadContext *tc); 431 432 inline void hwBegin(flags f, System *sys, uint64_t frame, std::string sm, 433 std::string st) 434 { 435 if (!enabled()) 436 return; 437 438 int sysi = getSys(sys); 439 int smi = getSm(sysi, sm, frame); 440 add(OP_BEGIN, FL_HW | f, 0, smi, getSt(sm, st)); 441 if (f & FL_BAD) 442 warn("BAD state encountered: at cycle %d: %s\n", curTick(), st); 443 } 444 445 inline void hwQ(flags f, System *sys, uint64_t frame, std::string sm, 446 std::string q, uint64_t qid, System *q_sys = NULL, int32_t count = 1) 447 { 448 if (!enabled()) 449 return; 450 451 int sysi = getSys(sys); 452 int qi = getQ(q_sys ? getSys(q_sys) : sysi, q, qid); 453 DPRINTFS(AnnotateQ, sys, 454 "hwQ: %s[%#x] cur size %d %d bytes: %d adding: %d\n", 455 q, qid, qSize[qi-1], qData[qi-1].size(), qBytes[qi-1], count); 456 doQ(sys, FL_HW | f, 0, getSm(sysi, sm, frame), q, qi, count); 457 458 } 459 460 inline void hwDq(flags f, System *sys, uint64_t frame, std::string sm, 461 std::string q, uint64_t qid, System *q_sys = NULL, int32_t count = 1) 462 { 463 if (!enabled()) 464 return; 465 466 int sysi = getSys(sys); 467 int qi = getQ(q_sys ? getSys(q_sys) : sysi, q, qid); 468 DPRINTFS(AnnotateQ, sys, 469 "hwDQ: %s[%#x] cur size %d %d bytes: %d removing: %d\n", 470 q, qid, qSize[qi-1], qData[qi-1].size(), qBytes[qi-1], count); 471 doDq(sys, FL_HW | f, 0, getSm(sysi,sm, frame), q, qi, count); 472 } 473 474 inline void hwPq(flags f, System *sys, uint64_t frame, std::string sm, 475 std::string q, uint64_t qid, System *q_sys = NULL, int32_t count = 1) 476 { 477 if (!enabled()) 478 return; 479 480 int sysi = getSys(sys); 481 int qi = getQ(q_sys ? getSys(q_sys) : sysi, q, qid); 482 DPRINTFS(AnnotateQ, sys, 483 "hwPQ: %s[%#x] cur size %d %d bytes: %d peeking: %d\n", 484 q, qid, qSize[qi-1], qData[qi-1].size(), qBytes[qi-1], count); 485 add(OP_PEEK, FL_HW | f, 0, getSm(sysi, sm, frame), qi, count); 486 } 487 488 inline void hwRq(flags f, System *sys, uint64_t frame, std::string sm, 489 std::string q, uint64_t qid, System *q_sys = NULL, int32_t count = 1) 490 { 491 if (!enabled()) 492 return; 493 494 int sysi = getSys(sys); 495 int qi = getQ(q_sys ? getSys(q_sys) : sysi, q, qid); 496 DPRINTFS(AnnotateQ, sys, 497 "hwRQ: %s[%#x] cur size %d %d bytes: %d reserving: %d\n", 498 q, qid, qSize[qi-1], qData[qi-1].size(), qBytes[qi-1], count); 499 add(OP_RESERVE, FL_HW | f, 0, getSm(sysi, sm, frame), qi, count); 500 } 501 502 inline void hwWf(flags f, System *sys, uint64_t frame, std::string sm, 503 std::string q, uint64_t qid, System *q_sys = NULL, int32_t count = 1) 504 { 505 if (!enabled()) 506 return; 507 508 int sysi = getSys(sys); 509 int qi = getQ(q_sys ? getSys(q_sys) : sysi, q, qid); 510 add(OP_WAIT_FULL, FL_HW | f, 0, getSm(sysi, sm, frame), qi, count); 511 } 512 513 inline void hwWe(flags f, System *sys, uint64_t frame, std::string sm, 514 std::string q, uint64_t qid, System *q_sys = NULL, int32_t count = 1) 515 { 516 if (!enabled()) 517 return; 518 519 int sysi = getSys(sys); 520 int qi = getQ(q_sys ? getSys(q_sys) : sysi, q, qid); 521 add(OP_WAIT_EMPTY, FL_HW | f, 0, getSm(sysi, sm, frame), qi, count); 522 } 523 524 public: 525 CPA(Params *p); 526 void startup(); 527 528 uint64_t getFrame(ThreadContext *tc); 529 530 static bool available() { return true; } 531 532 bool 533 enabled() 534 { 535 if (!this) 536 return false; 537 return _enabled; 538 } 539 540 void dump(bool all); 541 void dumpKey(); 542 543 void serialize(CheckpointOut &cp) const override; 544 void unserialize(CheckpointIn &cp) override; 545}; 546#endif // !CP_ANNOTATE 547 548#endif //__BASE__CP_ANNOTATE_HH__ 549 550