/* * Copyright (c) 2006-2009 The Regents of The University of Michigan * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer; * redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution; * neither the name of the copyright holders nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * Authors: Ali Saidi */ #include "base/cp_annotate.hh" #include "arch/generic/linux/threadinfo.hh" #include "arch/utility.hh" #include "base/callback.hh" #include "base/loader/object_file.hh" #include "base/output.hh" #include "base/trace.hh" #include "config/the_isa.hh" #include "cpu/thread_context.hh" #include "debug/Annotate.hh" #include "debug/AnnotateVerbose.hh" #include "sim/arguments.hh" #include "sim/core.hh" #include "sim/sim_exit.hh" #include "sim/system.hh" struct CPAIgnoreSymbol { const char *symbol; size_t len; }; #define CPA_IGNORE_SYMBOL(sym) { #sym, sizeof(#sym) } CPAIgnoreSymbol ignoreSymbols[] = { CPA_IGNORE_SYMBOL("m5a_"), CPA_IGNORE_SYMBOL("ret_from_sys_call"), CPA_IGNORE_SYMBOL("ret_from_reschedule"), CPA_IGNORE_SYMBOL("_spin_"), CPA_IGNORE_SYMBOL("local_bh_"), CPA_IGNORE_SYMBOL("restore_all"), CPA_IGNORE_SYMBOL("Call_Pal_"), CPA_IGNORE_SYMBOL("pal_post_interrupt"), CPA_IGNORE_SYMBOL("rti_to_"), CPA_IGNORE_SYMBOL("sys_int_2"), CPA_IGNORE_SYMBOL("sys_interrupt"), CPA_IGNORE_SYMBOL("normal_int"), CPA_IGNORE_SYMBOL("TRAP_INTERRUPT_10_"), CPA_IGNORE_SYMBOL("Trap_Interrupt"), CPA_IGNORE_SYMBOL("do_entInt"), CPA_IGNORE_SYMBOL("__do_softirq"), CPA_IGNORE_SYMBOL("_end"), CPA_IGNORE_SYMBOL("entInt"), CPA_IGNORE_SYMBOL("entSys"), {0,0} }; #undef CPA_IGNORE_SYMBOL using namespace std; using namespace TheISA; bool CPA::exists; CPA *CPA::_cpa; class AnnotateDumpCallback : public Callback { private: CPA *cpa; public: virtual void process(); AnnotateDumpCallback(CPA *_cpa) : cpa(_cpa) {} }; void AnnotateDumpCallback::process() { cpa->dump(true); cpa->dumpKey(); } CPA::CPA(Params *p) : SimObject(p), numSm(0), numSmt(0), numSys(0), numQs(0), conId(0) { if (exists) fatal("Multiple annotation objects found in system"); exists = true; _enabled = p->enabled; _cpa = this; vector::iterator i; i = p->user_apps.begin(); while (i != p->user_apps.end()) { ObjectFile *of = createObjectFile(*i); string sf; if (!of) fatal("Couldn't load symbols from file: %s\n", *i); sf = *i; sf.erase(0, sf.rfind('/') + 1);; DPRINTFN("file %s short: %s\n", *i, sf); userApp[sf] = new SymbolTable; bool result1 = of->loadGlobalSymbols(userApp[sf]); bool result2 = of->loadLocalSymbols(userApp[sf]); if (!result1 || !result2) panic("blah"); assert(result1 && result2); i++; } } void CPA::startup() { osbin = simout.create("annotate.bin", true); // MAGIC version number 'M''5''A'N' + version/capabilities ah.version = 0x4D35414E00000101ULL; ah.num_recs = 0; ah.key_off = 0; osbin->write((char*)&ah, sizeof(AnnotateHeader)); registerExitCallback(new AnnotateDumpCallback(this)); } uint64_t CPA::getFrame(ThreadContext *tc) { // This code is ISA specific and will need to be changed // if the annotation code is used for something other than Alpha return (tc->readMiscRegNoEffect(TheISA::IPR_PALtemp23) & ~ULL(0x3FFF)); } void CPA::swSmBegin(ThreadContext *tc) { if (!enabled()) return; Arguments args(tc); std::string st; Addr junk; char sm[50]; if (!TheISA::inUserMode(tc)) debugSymbolTable->findNearestSymbol( tc->readIntReg(ReturnAddressReg), st, junk); CopyStringOut(tc, sm, args[0], 50); System *sys = tc->getSystemPtr(); StringWrap name(sys->name()); if (!sm[0]) warn("Got null SM at tick %d\n", curTick()); int sysi = getSys(sys); int smi = getSm(sysi, sm, args[1]); DPRINTF(Annotate, "Starting machine: %s(%d) sysi: %d id: %#x\n", sm, smi, sysi, args[1]); DPRINTF(Annotate, "smMap[%d] = %d, %s, %#x\n", smi, smMap[smi-1].first, smMap[smi-1].second.first, smMap[smi-1].second.second); uint64_t frame = getFrame(tc); StackId sid = StackId(sysi, frame); // check if we need to link to the previous state machine int flags = args[2]; if (flags & FL_LINK) { if (smStack[sid].size()) { int prev_smi = smStack[sid].back(); DPRINTF(Annotate, "Linking from %d to state machine %s(%d) [%#x]\n", prev_smi, sm, smi, args[1]); if (lnMap[smi]) DPRINTF(Annotate, "LnMap already contains entry for %d of %d\n", smi, lnMap[smi]); assert(lnMap[smi] == 0); lnMap[smi] = prev_smi; add(OP_LINK, FL_NONE, tc->contextId(), prev_smi, smi); } else { DPRINTF(Annotate, "Not Linking to state machine %s(%d) [%#x]\n", sm, smi, args[1]); } } smStack[sid].push_back(smi); DPRINTF(Annotate, "Stack Now (%#X):\n", frame); for (int x = smStack[sid].size()-1; x >= 0; x--) DPRINTF(Annotate, "-- %d\n", smStack[sid][x]); // reset the sw state exculsion to false if (swExpl[sid]) swExpl[sid] = false; Id id = Id(sm, frame); if (scLinks[sysi-1][id]) { AnnDataPtr an = scLinks[sysi-1][id]; scLinks[sysi-1].erase(id); an->stq = smi; an->dump = true; DPRINTF(Annotate, "Found prev unknown linking from %d to state machine %s(%d)\n", an->sm, sm, smi); if (lnMap[smi]) DPRINTF(Annotate, "LnMap already contains entry for %d of %d\n", smi, lnMap[smi]); assert(lnMap[smi] == 0); lnMap[smi] = an->sm; } // add a new begin ifwe have that info if (st != "") { DPRINTF(Annotate, "st: %s smi: %d stCache.size %d\n", st, smi, stCache.size()); int sti = getSt(sm, st); lastState[smi] = sti; add(OP_BEGIN, FL_NONE, tc->contextId(), smi, sti); } } void CPA::swSmEnd(ThreadContext *tc) { if (!enabled()) return; Arguments args(tc); char sm[50]; CopyStringOut(tc, sm, args[0], 50); System *sys = tc->getSystemPtr(); doSwSmEnd(sys, tc->contextId(), sm, getFrame(tc)); } void CPA::doSwSmEnd(System *sys, int cpuid, string sm, uint64_t frame) { int sysi = getSys(sys); StackId sid = StackId(sysi, frame); // reset the sw state exculsion to false if (swExpl[sid]) swExpl[sid] = false; int smib = smStack[sid].back(); StringWrap name(sys->name()); DPRINTF(Annotate, "Ending machine: %s[%d, %#x] (%d?)\n", sm, sysi, frame, smib); if (!smStack[sid].size() || smMap[smib-1].second.first != sm) { DPRINTF(Annotate, "State Machine not unwinding correctly. sid: %d, %#x" " top of stack: %s Current Stack:\n", sysi, frame, smMap[smib-1].second.first); for (int x = smStack[sid].size()-1; x >= 0; x--) DPRINTF(Annotate, "-- %d\n", smStack[sid][x]); DPRINTF(Annotate, "Ending machine: %s; end stack: %s\n", sm, smMap[smib-1].second.first); warn("State machine stack not unwinding correctly at %d\n", curTick()); } else { DPRINTF(Annotate, "State machine ending:%s sysi:%d id:%#x back:%d getSm:%d\n", sm, sysi, smMap[smib-1].second.second, smStack[sid].back(), getSm(sysi, sm, smMap[smib-1].second.second)); assert(getSm(sysi, sm, smMap[smib-1].second.second) == smStack[sid].back()); int smi = smStack[sid].back(); smStack[sid].pop_back(); if (lnMap[smi]) { DPRINTF(Annotate, "Linking %d back to %d\n", smi, lnMap[smi]); add(OP_LINK, FL_NONE, cpuid, smi, lnMap[smi]); lnMap.erase(smi); } if (smStack[sid].size()) { add(OP_BEGIN, FL_NONE, cpuid, smi, lastState[smi]); } DPRINTF(Annotate, "Stack Now:\n"); for (int x = smStack[sid].size()-1; x >= 0; x--) DPRINTF(Annotate, "-- %d\n", smStack[sid][x]); } } void CPA::swExplictBegin(ThreadContext *tc) { if (!enabled()) return; Arguments args(tc); char st[50]; CopyStringOut(tc, st, args[1], 50); StringWrap name(tc->getSystemPtr()->name()); DPRINTF(Annotate, "Explict begin of state %s\n", st); uint32_t flags = args[0]; if (flags & FL_BAD) warn("BAD state encountered: at cycle %d: %s\n", curTick(), st); swBegin(tc->getSystemPtr(), tc->contextId(), st, getFrame(tc), true, args[0]); } void CPA::swAutoBegin(ThreadContext *tc, Addr next_pc) { if (!enabled()) return; string sym; Addr sym_addr = 0; if (!TheISA::inUserMode(tc)) { debugSymbolTable->findNearestSymbol(next_pc, sym, sym_addr); } else { Linux::ThreadInfo ti(tc); string app = ti.curTaskName(); if (userApp.count(app)) userApp[app]->findNearestSymbol(next_pc, sym, sym_addr); } if (sym_addr) swBegin(tc->getSystemPtr(), tc->contextId(), sym, getFrame(tc)); } void CPA::swBegin(System *sys, int cpuid, std::string st, uint64_t frame, bool expl, int flags) { int x = 0; int len; while (ignoreSymbols[x].len) { len = ignoreSymbols[x].len; if (!st.compare(0,len, ignoreSymbols[x].symbol, len)) return; x++; } int sysi = getSys(sys); StackId sid = StackId(sysi, frame); // if expl is true suspend symbol table based states if (!smStack[sid].size()) return; if (!expl && swExpl[sid]) return; if (expl) swExpl[sid] = true; DPRINTFS(AnnotateVerbose, sys, "SwBegin: %s sysi: %d\n", st, sysi); int smi = smStack[sid].back(); int sti = getSt(smMap[smi-1].second.first, st); if (lastState[smi] != sti) { lastState[smi] = sti; add(OP_BEGIN, flags, cpuid, smi, sti); } } void CPA::swEnd(ThreadContext *tc) { if (!enabled()) return; std::string st; Addr junk; if (!TheISA::inUserMode(tc)) debugSymbolTable->findNearestSymbol( tc->readIntReg(ReturnAddressReg), st, junk); System *sys = tc->getSystemPtr(); StringWrap name(sys->name()); int sysi = getSys(sys); StackId sid = StackId(sysi, getFrame(tc)); if (!smStack[sid].size()) { DPRINTF(Annotate, "Explict end of State: %s IGNORED\n", st); return; } DPRINTF(Annotate, "Explict end of State: %s\n", st); // return back to symbol table based states swExpl[sid] = false; int smi = smStack[sid].back(); if (st != "") { int sti = getSt(smMap[smi-1].second.first, st); lastState[smi] = sti; add(OP_BEGIN, FL_NONE, tc->contextId(), smi, sti); } } void CPA::swQ(ThreadContext *tc) { if (!enabled()) return; char q[50]; Arguments args(tc); uint64_t id = args[0]; CopyStringOut(tc, q, args[1], 50); int32_t count = args[2]; System *sys = tc->getSystemPtr(); int sysi = getSys(sys); StackId sid = StackId(sysi, getFrame(tc)); if (!smStack[sid].size()) return; int smi = smStack[sid].back(); if (swExpl[sid]) swExpl[sid] = false; int qi = getQ(sysi, q, id); if (count == 0) { //warn("Tried to queue 0 bytes in %s, ignoring\n", q); return; } DPRINTFS(AnnotateQ, sys, "swQ: %s[%#x] cur size %d %d bytes: %d adding: %d\n", q, id, qSize[qi-1], qData[qi-1].size(), qBytes[qi-1], count); doQ(sys, FL_NONE, tc->contextId(), smi, q, qi, count); } void CPA::swDq(ThreadContext *tc) { if (!enabled()) return; char q[50]; Arguments args(tc); uint64_t id = args[0]; CopyStringOut(tc, q, args[1], 50); int32_t count = args[2]; System *sys = tc->getSystemPtr(); int sysi = getSys(sys); StackId sid = StackId(sysi, getFrame(tc)); if (!smStack[sid].size()) return; int smi = smStack[sid].back(); int qi = getQ(sysi, q, id); if (swExpl[sid]) swExpl[sid] = false; DPRINTFS(AnnotateQ, sys, "swDq: %s[%#x] cur size %d %d bytes: %d removing: %d\n", q, id, qSize[qi-1], qData[qi-1].size(), qBytes[qi-1], count); assert(count != 0); doDq(sys, FL_NONE, tc->contextId(), smi, q, qi, count); } void CPA::swPq(ThreadContext *tc) { if (!enabled()) return; char q[50]; Arguments args(tc); uint64_t id = args[0]; CopyStringOut(tc, q, args[1], 50); System *sys = tc->getSystemPtr(); int32_t count = args[2]; int sysi = getSys(sys); StackId sid = StackId(sysi, getFrame(tc)); if (!smStack[sid].size()) return; int smi = smStack[sid].back(); int qi = getQ(sysi, q, id); if (swExpl[sid]) swExpl[sid] = false; DPRINTFS(AnnotateQ, sys, "swPq: %s [%#x] cur size %d %d bytes: %d peeking: %d\n", q, id, qSize[qi-1], qData[qi-1].size(), qBytes[qi-1], count); assert(count != 0); if (qBytes[qi-1] < count) { dump(true); dumpKey(); fatal("Queue %s peeking with not enough bytes available in queue!\n", q); } add(OP_PEEK, FL_NONE, tc->contextId(), smi, qi, count); } void CPA::swRq(ThreadContext *tc) { if (!enabled()) return; char q[50]; Arguments args(tc); uint64_t id = args[0]; CopyStringOut(tc, q, args[1], 50); System *sys = tc->getSystemPtr(); int32_t count = args[2]; int sysi = getSys(sys); StackId sid = StackId(sysi, getFrame(tc)); if (!smStack[sid].size()) return; int smi = smStack[sid].back(); int qi = getQ(sysi, q, id); if (swExpl[sid]) swExpl[sid] = false; DPRINTFS(AnnotateQ, sys, "swRq: %s [%#x] cur size %d %d bytes: %d reserve: %d\n", q, id, qSize[qi-1], qData[qi-1].size(), qBytes[qi-1], count); assert(count != 0); add(OP_RESERVE, FL_NONE, tc->contextId(), smi, qi, count); } void CPA::swWf(ThreadContext *tc) { if (!enabled()) return; char q[50]; Arguments args(tc); uint64_t id = args[0]; CopyStringOut(tc, q, args[1], 50); System *sys = tc->getSystemPtr(); int32_t count = args[3]; int sysi = getSys(sys); StackId sid = StackId(sysi, getFrame(tc)); if (!smStack[sid].size()) return; int smi = smStack[sid].back(); int qi = getQ(sysi, q, id); add(OP_WAIT_FULL, FL_NONE, tc->contextId(), smi, qi, count); if (!!args[2]) { char sm[50]; CopyStringOut(tc, sm, args[2], 50); doSwSmEnd(tc->getSystemPtr(), tc->contextId(), sm, getFrame(tc)); } } void CPA::swWe(ThreadContext *tc) { if (!enabled()) return; char q[50]; Arguments args(tc); uint64_t id = args[0]; CopyStringOut(tc, q, args[1], 50); System *sys = tc->getSystemPtr(); int32_t count = args[3]; int sysi = getSys(sys); StackId sid = StackId(sysi, getFrame(tc)); if (!smStack[sid].size()) return; int smi = smStack[sid].back(); int qi = getQ(sysi, q, id); add(OP_WAIT_EMPTY, FL_NONE, tc->contextId(), smi, qi, count); if (!!args[2]) { char sm[50]; CopyStringOut(tc, sm, args[2], 50); doSwSmEnd(tc->getSystemPtr(), tc->contextId(), sm, getFrame(tc)); } } void CPA::swSq(ThreadContext *tc) { if (!enabled()) return; char q[50]; Arguments args(tc); uint64_t id = args[0]; CopyStringOut(tc, q, args[1], 50); System *sys = tc->getSystemPtr(); StringWrap name(sys->name()); int32_t size = args[2]; int flags = args[3]; int sysi = getSys(sys); StackId sid = StackId(sysi, getFrame(tc)); if (!smStack[sid].size()) return; int smi = smStack[sid].back(); int qi = getQ(sysi, q, id); DPRINTF(AnnotateQ, "swSq: %s [%#x] cur size: %d bytes: %d, new size: %d\n", q, id, qSize[qi-1], qBytes[qi-1], size); if (FL_RESET & flags) { DPRINTF(AnnotateQ, "Resetting Queue %s\n", q); add(OP_SIZE_QUEUE, FL_NONE, tc->contextId(), smi, qi, 0); qData[qi-1].clear(); qSize[qi-1] = 0; qBytes[qi-1] = 0; } if (qBytes[qi-1] < size) doQ(sys, FL_NONE, tc->contextId(), smi, q, qi, size - qBytes[qi-1]); else if (qBytes[qi-1] > size) { DPRINTF(AnnotateQ, "removing for resize of queue %s\n", q); add(OP_SIZE_QUEUE, FL_NONE, tc->contextId(), smi, qi, size); if (size <= 0) { qData[qi-1].clear(); qSize[qi-1] = 0; qBytes[qi-1] = 0; return; } int need = qBytes[qi-1] - size; qBytes[qi-1] = size; while (need > 0) { int32_t tail_bytes = qData[qi-1].back()->data; if (qSize[qi-1] <= 0 || qBytes[qi-1] < 0) { dump(true); dumpKey(); fatal("Queue %s had inconsistancy when doing size queue!\n", q); } if (tail_bytes > need) { qData[qi-1].back()->data -= need; need = 0; } else if (tail_bytes == need) { qData[qi-1].pop_back(); qSize[qi-1]--; need = 0; } else { qData[qi-1].pop_back(); qSize[qi-1]--; need -= tail_bytes; } } } } void CPA::swAq(ThreadContext *tc) { if (!enabled()) return; char q[50]; Arguments args(tc); uint64_t id = args[0]; CopyStringOut(tc, q, args[1], 50); System *sys = tc->getSystemPtr(); StringWrap name(sys->name()); int32_t size = args[2]; int sysi = getSys(sys); int qi = getQ(sysi, q, id); if (qBytes[qi-1] != size) { DPRINTF(AnnotateQ, "Queue %s [%#x] has inconsintant size\n", q, id); //dump(true); //dumpKey(); std::list::iterator ai = qData[qi-1].begin(); int x = 0; while (ai != qData[qi-1].end()) { DPRINTF(AnnotateQ, "--Element %d size %d\n", x, (*ai)->data); ai++; x++; } warn("%d: Queue Assert: SW said there should be %d byte(s) in %s," "however there are %d byte(s)\n", curTick(), size, q, qBytes[qi-1]); DPRINTF(AnnotateQ, "%d: Queue Assert: SW said there should be %d" " byte(s) in %s, however there are %d byte(s)\n", curTick(), size, q, qBytes[qi-1]); } } void CPA::swLink(ThreadContext *tc) { if (!enabled()) return; char lsm[50]; Arguments args(tc); CopyStringOut(tc, lsm, args[0], 50); System *sys = tc->getSystemPtr(); StringWrap name(sys->name()); int sysi = getSys(sys); StackId sid = StackId(sysi, getFrame(tc)); if (!smStack[sid].size()) return; int smi = smStack[sid].back(); int lsmi = getSm(sysi, lsm, args[1]); DPRINTF(Annotate, "Linking from %d to state machine %s(%d) [%#x]\n", smi, lsm, lsmi, args[1]); if (lnMap[lsmi]) DPRINTF(Annotate, "LnMap already contains entry for %d of %d\n", lsmi, lnMap[lsmi]); assert(lnMap[lsmi] == 0); lnMap[lsmi] = smi; add(OP_LINK, FL_NONE, tc->contextId(), smi, lsmi); if (!!args[2]) { char sm[50]; CopyStringOut(tc, sm, args[2], 50); doSwSmEnd(tc->getSystemPtr(), tc->contextId(), sm, getFrame(tc)); } } void CPA::swIdentify(ThreadContext *tc) { if (!enabled()) return; Arguments args(tc); int sysi = getSys(tc->getSystemPtr()); StackId sid = StackId(sysi, getFrame(tc)); if (!smStack[sid].size()) return; int smi = smStack[sid].back(); DPRINTFS(Annotate, tc->getSystemPtr(), "swIdentify: id %#X\n", args[0]); add(OP_IDENT, FL_NONE, tc->contextId(), smi, 0, args[0]); } uint64_t CPA::swGetId(ThreadContext *tc) { if (!enabled()) return 0; uint64_t id = ++conId; int sysi = getSys(tc->getSystemPtr()); StackId sid = StackId(sysi, getFrame(tc)); if (!smStack[sid].size()) panic("swGetId called without a state machine stack!"); int smi = smStack[sid].back(); DPRINTFS(Annotate, tc->getSystemPtr(), "swGetId: id %#X\n", id); add(OP_IDENT, FL_NONE, tc->contextId(), smi, 0, id); return id; } void CPA::swSyscallLink(ThreadContext *tc) { if (!enabled()) return; char lsm[50]; Arguments args(tc); CopyStringOut(tc, lsm, args[0], 50); System *sys = tc->getSystemPtr(); StringWrap name(sys->name()); int sysi = getSys(sys); Id id = Id(lsm, getFrame(tc)); StackId sid = StackId(sysi, getFrame(tc)); if (!smStack[sid].size()) return; int smi = smStack[sid].back(); DPRINTF(Annotate, "Linking from %d to state machine %s(UNKNOWN)\n", smi, lsm); if (scLinks[sysi-1][id]) DPRINTF(Annotate, "scLinks already contains entry for system %d %s[%x] of %d\n", sysi, lsm, getFrame(tc), scLinks[sysi-1][id]); assert(scLinks[sysi-1][id] == 0); scLinks[sysi-1][id] = add(OP_LINK, FL_NONE, tc->contextId(), smi, 0xFFFF); scLinks[sysi-1][id]->dump = false; if (!!args[1]) { char sm[50]; CopyStringOut(tc, sm, args[1], 50); doSwSmEnd(tc->getSystemPtr(), tc->contextId(), sm, getFrame(tc)); } } CPA::AnnDataPtr CPA::add(int t, int f, int c, int sm, int stq, int32_t d) { AnnDataPtr an = std::make_shared(); an->time = curTick(); an->data = d; an->orig_data = d; an->op = t; an->flag = f; an->sm = sm; an->stq = stq; an->cpu = c; an->dump = true; data.push_back(an); DPRINTF(AnnotateVerbose, "Annotate: op: %d flags: 0x%x sm: %d state: %d time: %d, data: %d\n", an->op, an->flag, an->sm, an->stq, an->time, an->data); // Don't dump Links because we might be setting no-dump on it if (an->op != OP_LINK) dump(false); return an; } void CPA::dumpKey() { std::streampos curpos = osbin->tellp(); ah.key_off = curpos; // Output the various state machines and their corresponding states *osbin << "# Automatically generated state machine descriptor file" << endl; *osbin << "sms = {}" << endl << endl; vector state_machines; state_machines.resize(numSmt+1); // State machines, id -> states SCache::iterator i = smtCache.begin(); while (i != smtCache.end()) { state_machines[i->second] = i->first; i++; } for (int x = 1; x < state_machines.size(); x++) { vector states; states.resize(numSt[x-1]+1); assert(x-1 < stCache.size()); SCache::iterator i = stCache[x-1].begin(); while (i != stCache[x-1].end()) { states[i->second] = i->first; i++; } *osbin << "sms[\"" << state_machines[x] << "\"] = [\"NULL\""; for (int y = 1; y < states.size(); y++) *osbin << ", \"" << states[y] << "\""; *osbin << "]" << endl; } *osbin << endl << endl << endl; // state machine number -> system, name, id *osbin << "smNum = [\"NULL\""; for (int x = 0; x < smMap.size(); x++) *osbin << ", (" << smMap[x].first << ", \"" << smMap[x].second.first << "\", " << smMap[x].second.second << ")"; *osbin << "]" << endl; *osbin << endl << endl << endl; // Output the systems vector systems; systems.resize(numSys+1); NameCache::iterator i2 = nameCache.begin(); while (i2 != nameCache.end()) { systems[i2->second.second] = i2->second.first; i2++; } *osbin << "sysNum = [\"NULL\""; for (int x = 1; x < systems.size(); x++) { *osbin << ", \"" << systems[x] << "\""; } *osbin << "]" << endl; // queue number -> system, qname, qid *osbin << "queues = [\"NULL\""; for (int x = 0; x < qMap.size(); x++) *osbin << ", (" << qMap[x].first << ", \"" << qMap[x].second.first << "\", " << qMap[x].second.second << ")"; *osbin << "]" << endl; *osbin << "smComb = [s for s in [(i,r) for i in xrange(1,len(sysNum)) " << "for r in xrange (1,len(smNum))]]" << endl; ah.key_len = osbin->tellp() - curpos; // output index curpos = osbin->tellp(); ah.idx_off = curpos; for (int x = 0; x < annotateIdx.size(); x++) osbin->write((char*)&annotateIdx[x], sizeof(uint64_t)); ah.idx_len = osbin->tellp() - curpos; osbin->seekp(0); osbin->write((char*)&ah, sizeof(AnnotateHeader)); osbin->flush(); } void CPA::dump(bool all) { list::iterator i; i = data.begin(); if (i == data.end()) return; // Dump the data every if (!all && data.size() < 10000) return; DPRINTF(Annotate, "Writing %d\n", data.size()); while (i != data.end()) { AnnDataPtr an = *i; // If we can't dump this record, hold here if (!an->dump && !all) break; ah.num_recs++; if (ah.num_recs % 100000 == 0) annotateIdx.push_back(osbin->tellp()); osbin->write((char*)&(an->time), sizeof(an->time)); osbin->write((char*)&(an->orig_data), sizeof(an->orig_data)); osbin->write((char*)&(an->sm), sizeof(an->sm)); osbin->write((char*)&(an->stq), sizeof(an->stq)); osbin->write((char*)&(an->op), sizeof(an->op)); osbin->write((char*)&(an->flag), sizeof(an->flag)); osbin->write((char*)&(an->cpu), sizeof(an->cpu)); i++; } if (data.begin() != i) data.erase(data.begin(), i); if (all) osbin->flush(); } void CPA::doQ(System *sys, int flags, int cpuid, int sm, string q, int qi, int count) { qSize[qi-1]++; qBytes[qi-1] += count; if (qSize[qi-1] > 2501 || qBytes[qi-1] > 2000000000) warn("Queue %s is %d elements/%d bytes, " "maybe things aren't being removed?\n", q, qSize[qi-1], qBytes[qi-1]); if (flags & FL_QOPP) qData[qi-1].push_front(add(OP_QUEUE, flags, cpuid, sm, qi, count)); else qData[qi-1].push_back(add(OP_QUEUE, flags, cpuid, sm, qi, count)); DPRINTFS(AnnotateQ, sys, "Queing in queue %s size now %d/%d\n", q, qSize[qi-1], qBytes[qi-1]); assert(qSize[qi-1] >= 0); assert(qBytes[qi-1] >= 0); } void CPA::doDq(System *sys, int flags, int cpuid, int sm, string q, int qi, int count) { StringWrap name(sys->name()); if (count == -1) { add(OP_DEQUEUE, flags, cpuid, sm, qi, count); qData[qi-1].clear(); qSize[qi-1] = 0; qBytes[qi-1] = 0; DPRINTF(AnnotateQ, "Dequeing all data in queue %s size now %d/%d\n", q, qSize[qi-1], qBytes[qi-1]); return; } assert(count > 0); if (qSize[qi-1] <= 0 || qBytes[qi-1] <= 0 || !qData[qi-1].size()) { dump(true); dumpKey(); fatal("Queue %s dequing with no data available in queue!\n", q); } assert(qSize[qi-1] >= 0); assert(qBytes[qi-1] >= 0); assert(qData[qi-1].size()); int32_t need = count; qBytes[qi-1] -= count; if (qBytes[qi-1] < 0) { dump(true); dumpKey(); fatal("Queue %s dequing with no bytes available in queue!\n", q); } while (need > 0) { int32_t head_bytes = qData[qi-1].front()->data; if (qSize[qi-1] <= 0 || qBytes[qi-1] < 0) { dump(true); dumpKey(); fatal("Queue %s dequing with nothing in queue!\n", q); } if (head_bytes > need) { qData[qi-1].front()->data -= need; need = 0; } else if (head_bytes == need) { qData[qi-1].pop_front(); qSize[qi-1]--; need = 0; } else { qData[qi-1].pop_front(); qSize[qi-1]--; need -= head_bytes; } } add(OP_DEQUEUE, flags, cpuid, sm, qi, count); DPRINTF(AnnotateQ, "Dequeing in queue %s size now %d/%d\n", q, qSize[qi-1], qBytes[qi-1]); } void CPA::serialize(CheckpointOut &cp) const { SERIALIZE_SCALAR(numSm); SERIALIZE_SCALAR(numSmt); arrayParamOut(os, "numSt", numSt); arrayParamOut(os, "numQ", numQ); SERIALIZE_SCALAR(numSys); SERIALIZE_SCALAR(numQs); SERIALIZE_SCALAR(conId); arrayParamOut(os, "qSize", qSize); arrayParamOut(os, "qSize", qSize); arrayParamOut(os, "qBytes", qBytes); SCache::iterator i; int x = 0, y = 0; // smtCache (SCache) x = 0; y = 0; i = smtCache.begin(); while (i != smtCache.end()) { paramOut(os, csprintf("smtCache%d.str", x), i->first); paramOut(os, csprintf("smtCache%d.int", x), i->second); x++; i++; } // stCache (StCache) for (x = 0; x < stCache.size(); x++) { i = stCache[x].begin(); y = 0; while (i != stCache[x].end()) { paramOut(os, csprintf("stCache%d_%d.str", x, y), i->first); paramOut(os, csprintf("stCache%d_%d.int", x, y), i->second); y++; i++; } } // qCache (IdCache) IdHCache::iterator idi; for (x = 0; x < qCache.size(); x++) { idi = qCache[x].begin(); y = 0; while (idi != qCache[x].end()) { paramOut(os, csprintf("qCache%d_%d.str", x, y), idi->first.first); paramOut(os, csprintf("qCache%d_%d.id", x, y), idi->first.second); paramOut(os, csprintf("qCache%d_%d.int", x, y), idi->second); y++; idi++; } } // smCache (IdCache) for (x = 0; x < smCache.size(); x++) { idi = smCache[x].begin(); y = 0; paramOut(os, csprintf("smCache%d", x), smCache[x].size()); while (idi != smCache[x].end()) { paramOut(os, csprintf("smCache%d_%d.str", x, y), idi->first.first); paramOut(os, csprintf("smCache%d_%d.id", x, y), idi->first.second); paramOut(os, csprintf("smCache%d_%d.int", x, y), idi->second); y++; idi++; } } // scLinks (ScCache) -- data not serialize // namecache (NameCache) NameCache::iterator ni; ni = nameCache.begin(); x = 0; while (ni != nameCache.end()) { paramOut(os, csprintf("nameCache%d.name", x), ni->first->name()); paramOut(os, csprintf("nameCache%d.str", x), ni->second.first); paramOut(os, csprintf("nameCache%d.int", x), ni->second.second); x++; ni++; } // smStack (SmStack) SmStack::iterator si; si = smStack.begin(); x = 0; paramOut(os, "smStackIdCount", smStack.size()); while (si != smStack.end()) { paramOut(os, csprintf("smStackId%d.sys", x), si->first.first); paramOut(os, csprintf("smStackId%d.frame", x), si->first.second); paramOut(os, csprintf("smStackId%d.count", x), si->second.size()); for (y = 0; y < si->second.size(); y++) paramOut(os, csprintf("smStackId%d_%d", x, y), si->second[y]); x++; si++; } // lnMap (LinkMap) x = 0; LinkMap::iterator li; li = lnMap.begin(); paramOut(os, "lnMapSize", lnMap.size()); while (li != lnMap.end()) { paramOut(os, csprintf("lnMap%d.smi", x), li->first); paramOut(os, csprintf("lnMap%d.lsmi", x), li->second); x++; li++; } // swExpl (vector) SwExpl::iterator swexpli; swexpli = swExpl.begin(); x = 0; paramOut(os, "swExplCount", swExpl.size()); while (swexpli != swExpl.end()) { paramOut(os, csprintf("swExpl%d.sys", x), swexpli->first.first); paramOut(os, csprintf("swExpl%d.frame", x), swexpli->first.second); paramOut(os, csprintf("swExpl%d.swexpl", x), swexpli->second); x++; swexpli++; } // lastState (IMap) x = 0; IMap::iterator ii; ii = lastState.begin(); paramOut(os, "lastStateSize", lastState.size()); while (ii != lastState.end()) { paramOut(os, csprintf("lastState%d.smi", x), ii->first); paramOut(os, csprintf("lastState%d.sti", x), ii->second); x++; ii++; } // smMap (IdMap) for (x = 0; x < smMap.size(); x++) { paramOut(os, csprintf("smMap%d.sys", x), smMap[x].first); paramOut(os, csprintf("smMap%d.smname", x), smMap[x].second.first); paramOut(os, csprintf("smMap%d.id", x), smMap[x].second.second); } // qMap (IdMap) for (x = 0; x < qMap.size(); x++) { paramOut(os, csprintf("qMap%d.sys", x), qMap[x].first); paramOut(os, csprintf("qMap%d.qname", x), qMap[x].second.first); paramOut(os, csprintf("qMap%d.id", x), qMap[x].second.second); } // qData (vector) for (x = 0; x < qData.size(); x++) { if (!qData[x].size()) continue; y = 0; for (auto &ann : qData[x]) { ann->serializeSection(os, csprintf("Q%d_%d", x, y)); y++; } } } void CPA::unserialize(CheckpointIn &cp) { UNSERIALIZE_SCALAR(numSm); UNSERIALIZE_SCALAR(numSmt); UNSERIALIZE_CONTAINER(numSt); UNSERIALIZE_CONTAINER(numQ); UNSERIALIZE_SCALAR(numSys); UNSERIALIZE_SCALAR(numQs); UNSERIALIZE_SCALAR(conId); UNSERIALIZE_CONTAINER(qSize); UNSERIALIZE_CONTAINER(qBytes); // smtCache (SCache string str; int smi; for (int x = 0; x < numSmt; x++) { paramIn(cp, csprintf("smtCache%d.str", x), str); paramIn(cp, csprintf("smtCache%d.int", x), smi); smtCache[str] = smi; } // stCache (StCache) stCache.resize(numSmt); for (int x = 0; x < numSmt; x++) { for (int y = 0; y < numSt[x]; y++) { paramIn(cp, csprintf("stCache%d_%d.str", x,y), str); paramIn(cp, csprintf("stCache%d_%d.int", x,y), smi); stCache[x][str] = smi; } } // qCache (IdCache) uint64_t id; qCache.resize(numSys); for (int x = 0; x < numSys; x++) { for (int y = 0; y < numQ[x]; y++) { paramIn(cp, csprintf("qCache%d_%d.str", x,y), str); paramIn(cp, csprintf("qCache%d_%d.id", x,y), id); paramIn(cp, csprintf("qCache%d_%d.int", x,y), smi); qCache[x][Id(str,id)] = smi; } } // smCache (IdCache) smCache.resize(numSys); for (int x = 0; x < numSys; x++) { int size; paramIn(cp, csprintf("smCache%d", x), size); for (int y = 0; y < size; y++) { paramIn(cp, csprintf("smCache%d_%d.str", x,y), str); paramIn(cp, csprintf("smCache%d_%d.id", x,y), id); paramIn(cp, csprintf("smCache%d_%d.int", x,y), smi); smCache[x][Id(str,id)] = smi; } } // scLinks (ScCache) -- data not serialized, just creating one per sys for (int x = 0; x < numSys; x++) scLinks.push_back(ScHCache()); // nameCache (NameCache) for (int x = 0; x < numSys; x++) { System *sys; SimObject *sptr; string str; int sysi; objParamIn(cp, csprintf("nameCache%d.name", x), sptr); sys = dynamic_cast(sptr); paramIn(cp, csprintf("nameCache%d.str", x), str); paramIn(cp, csprintf("nameCache%d.int", x), sysi); nameCache[sys] = std::make_pair(str, sysi); } //smStack (SmStack) int smStack_size; paramIn(cp, "smStackIdCount", smStack_size); for (int x = 0; x < smStack_size; x++) { int sysi; uint64_t frame; int count; paramIn(cp, csprintf("smStackId%d.sys", x), sysi); paramIn(cp, csprintf("smStackId%d.frame", x), frame); paramIn(cp, csprintf("smStackId%d.count", x), count); StackId sid = StackId(sysi, frame); for (int y = 0; y < count; y++) { paramIn(cp, csprintf("smStackId%d_%d", x, y), smi); smStack[sid].push_back(smi); } } // lnMap (LinkMap) int lsmi; int lnMap_size; paramIn(cp, "lnMapSize", lnMap_size); for (int x = 0; x < lnMap_size; x++) { paramIn(cp, csprintf("lnMap%d.smi", x), smi); paramIn(cp, csprintf("lnMap%d.lsmi", x), lsmi); lnMap[smi] = lsmi; } // swExpl (vector) int swExpl_size; paramIn(cp, "swExplCount", swExpl_size); for (int x = 0; x < swExpl_size; x++) { int sysi; uint64_t frame; bool b; paramIn(cp, csprintf("swExpl%d.sys", x), sysi); paramIn(cp, csprintf("swExpl%d.frame", x), frame); paramIn(cp, csprintf("swExpl%d.swexpl", x), b); StackId sid = StackId(sysi, frame); swExpl[sid] = b; } // lastState (IMap) int sti; int lastState_size; paramIn(cp, "lastStateSize", lastState_size); for (int x = 0; x < lastState_size; x++) { paramIn(cp, csprintf("lastState%d.smi", x), smi); paramIn(cp, csprintf("lastState%d.sti", x), sti); lastState[smi] = sti; } //smMap (IdMap) smMap.resize(numSm); for (int x = 0; x < smMap.size(); x++) { paramIn(cp, csprintf("smMap%d.sys", x), smMap[x].first); paramIn(cp, csprintf("smMap%d.smname", x), smMap[x].second.first); paramIn(cp, csprintf("smMap%d.id", x), smMap[x].second.second); } //qMap (IdMap) qMap.resize(numQs); for (int x = 0; x < qMap.size(); x++) { paramIn(cp, csprintf("qMap%d.sys", x), qMap[x].first); paramIn(cp, csprintf("qMap%d.qname", x), qMap[x].second.first); paramIn(cp, csprintf("qMap%d.id", x), qMap[x].second.second); } // qData (vector) qData.resize(qSize.size()); for (int x = 0; x < qSize.size(); x++) { if (!qSize[x]) continue; for (int y = 0; y < qSize[x]; y++) { AnnDataPtr a = std::make_shared(); a->unserializeSection(cp, csprintf("Q%d_%d", x, y)); data.push_back(a); qData[x].push_back(a); } } } void CPA::AnnotateData::serialize(CheckpointOut &cp) const { SERIALIZE_SCALAR(time); SERIALIZE_SCALAR(data); SERIALIZE_SCALAR(sm); SERIALIZE_SCALAR(stq); SERIALIZE_SCALAR(op); SERIALIZE_SCALAR(flag); SERIALIZE_SCALAR(cpu); } void CPA::AnnotateData::unserialize(CheckpointIn &cp) { UNSERIALIZE_SCALAR(time); UNSERIALIZE_SCALAR(data); orig_data = data; UNSERIALIZE_SCALAR(sm); UNSERIALIZE_SCALAR(stq); UNSERIALIZE_SCALAR(op); UNSERIALIZE_SCALAR(flag); UNSERIALIZE_SCALAR(cpu); dump = true; } CPA* CPAParams::create() { return new CPA(this); }