cp_annotate.hh revision 10470:2c6a72e919f6
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 <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 §ion); 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 §ion); 546 547}; 548#endif // !CP_ANNOTATE 549 550#endif //__BASE__CP_ANNOTATE_HH__ 551 552