blob: 9209ffdd3ac69ee45a0531383cbf6d52cfd3591c [file] [log] [blame]
/*
* 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<string>::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<AnnDataPtr>::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<AnnotateData>();
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<string> 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<string> 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<string> 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<AnnDataPtr>::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<AnnotateList>)
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<System*>(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<AnnotateList>)
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<AnnotateData>();
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);
}