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