Merge changes 1344,1345 into donut

* changes:
  Fix the tracing code that keeps track of the Java method stack.
  Add a "-d time" option to stack_dump to dump the stack at the given time.
This commit is contained in:
Android (Google) Code Review
2009-05-11 17:28:21 -07:00
2 changed files with 75 additions and 27 deletions

View File

@@ -44,6 +44,7 @@ class StackFrame {
template <class FRAME, class BASE = CallStackBase>
class CallStack : public BASE {
public:
typedef FRAME frame_type;
typedef typename FRAME::symbol_type symbol_type;
typedef typename FRAME::symbol_type::region_type region_type;
typedef BASE base_type;
@@ -64,8 +65,12 @@ class CallStack : public BASE {
int getStackLevel() { return mTop; }
uint64_t getGlobalTime(uint64_t time) { return time + mSkippedTime; }
void showStack();
void showSnapshotStack();
void showStack(FILE *stream);
void showSnapshotStack(FILE *stream);
int mNumFrames;
FRAME *mFrames;
int mTop; // index of the next stack frame to write
private:
enum Action { NONE, PUSH, POP };
@@ -87,10 +92,6 @@ class CallStack : public BASE {
symbol_type mDummyFunction;
region_type mDummyRegion;
int mNumFrames;
FRAME *mFrames;
int mTop; // index of the next stack frame to write
int mJavaTop;
int mSnapshotNumFrames;
@@ -366,8 +367,11 @@ void CallStack<FRAME, BASE>::doPush(BBEvent *event, symbol_type *function)
// Check for stack overflow
if (mTop >= mNumFrames) {
// Don't show the stack by default because this generates a lot
// of output and this is seen by users if there is an error when
// post-processing the trace. But this is useful for debugging.
#if 0
showStack();
showStack(stderr);
#endif
fprintf(stderr, "Error: stack overflow (%d frames)\n", mTop);
exit(1);
@@ -391,17 +395,20 @@ void CallStack<FRAME, BASE>::doPush(BBEvent *event, symbol_type *function)
}
#if 0
// For debugging only. Show the stack before entering the kernel
// exception-handling code.
if (function->flags & symbol_type::kIsVectorStart) {
printf("stack before entering exception\n");
showStack();
showStack(stderr);
}
#endif
// If the previous function was a vector table, then pop it
// If the top of stack is a vector table, then pop it
// off before pushing on the new function. Also, change the
// return address for the new function to the return address
// from the vector table.
if ((mPrevFunction->flags & symbol_type::kIsVectorTable) && mTop > 0) {
if (mTop > 0
&& (mFrames[mTop - 1].function->flags & symbol_type::kIsVectorTable)) {
retAddr = mFrames[mTop - 1].addr;
doSimplePop(time);
}
@@ -426,9 +433,10 @@ void CallStack<FRAME, BASE>::doPush(BBEvent *event, symbol_type *function)
&& mTop > 0) {
// We are switching from kernel mode to user mode.
#if 0
// For debugging.
printf(" doPush(): popping to user mode, bb_addr: 0x%08x\n",
event->bb_addr);
showStack();
showStack(stderr);
#endif
do {
// Pop off the kernel frames until we reach the one that
@@ -445,6 +453,7 @@ void CallStack<FRAME, BASE>::doPush(BBEvent *event, symbol_type *function)
}
} while (mTop > 0);
#if 0
// For debugging
printf(" doPush() popping to level %d, using retAddr 0x%08x\n",
mTop, retAddr);
#endif
@@ -465,7 +474,7 @@ void CallStack<FRAME, BASE>::doSimplePush(symbol_type *function,
{
// Check for stack overflow
if (mTop >= mNumFrames) {
showStack();
showStack(stderr);
fprintf(stderr, "too many stack frames (%d)\n", mTop);
exit(1);
}
@@ -565,7 +574,13 @@ void CallStack<FRAME, BASE>::doPop(BBEvent *event, symbol_type *function,
// Compare the function with the one in the stack frame.
if (function == mFrames[stackLevel].function) {
// We found a matching function. We want to pop up to but not
// including this frame.
// including this frame. But allow popping this frame if this
// method called itself and we have a method pop.
if (allowMethodPop && function == mPrevFunction) {
// pop this frame
break;
}
// do not pop this frame
stackLevel += 1;
break;
}
@@ -604,9 +619,11 @@ void CallStack<FRAME, BASE>::doPop(BBEvent *event, symbol_type *function,
stackLevel = 1;
#if 0
// If we are popping off a large number of stack frames, then
// we might have a bug.
if (mTop - stackLevel > 7) {
printf("popping thru level %d\n", stackLevel);
showStack();
showStack(stderr);
}
#endif
@@ -675,7 +692,7 @@ CallStack<FRAME, BASE>::getMethodAction(BBEvent *event, symbol_type *function)
}
}
if (event->time >= sCurrentMethod.time) {
if (event->time >= sCurrentMethod.time && event->pid == sCurrentMethod.pid) {
if (addr == sCurrentMethod.addr || prevAddr == sCurrentMethod.addr) {
action = (sCurrentMethod.flags == 0) ? PUSH : POP;
// We found a match, so read the next record.
@@ -733,24 +750,26 @@ void CallStack<FRAME, BASE>::transitionFromJava(uint64_t time)
}
template<class FRAME, class BASE>
void CallStack<FRAME, BASE>::showStack()
void CallStack<FRAME, BASE>::showStack(FILE *stream)
{
fprintf(stderr, "mTop: %d skippedTime: %llu\n", mTop, mSkippedTime);
fprintf(stream, "mTop: %d skippedTime: %llu\n", mTop, mSkippedTime);
for (int ii = 0; ii < mTop; ++ii) {
fprintf(stderr, " %d: t %d gt %d f %x 0x%08x 0x%08x %s\n",
uint32_t addr = mFrames[ii].function->addr;
addr += mFrames[ii].function->region->vstart;
fprintf(stream, " %d: t %d gt %d f %x 0x%08x 0x%08x %s\n",
ii, mFrames[ii].time, mFrames[ii].global_time,
mFrames[ii].flags,
mFrames[ii].addr, mFrames[ii].function->addr,
mFrames[ii].addr, addr,
mFrames[ii].function->name);
}
}
template<class FRAME, class BASE>
void CallStack<FRAME, BASE>::showSnapshotStack()
void CallStack<FRAME, BASE>::showSnapshotStack(FILE *stream)
{
fprintf(stderr, "mSnapshotTop: %d\n", mSnapshotTop);
fprintf(stream, "mSnapshotTop: %d\n", mSnapshotTop);
for (int ii = 0; ii < mSnapshotTop; ++ii) {
fprintf(stderr, " %d: t %d f %x 0x%08x 0x%08x %s\n",
fprintf(stream, " %d: t %d f %x 0x%08x 0x%08x %s\n",
ii, mSnapshotFrames[ii].time, mSnapshotFrames[ii].flags,
mSnapshotFrames[ii].addr, mSnapshotFrames[ii].function->addr,
mSnapshotFrames[ii].function->name);

View File

@@ -15,6 +15,9 @@ typedef TraceReader<> TraceReaderType;
#include "parse_options-inl.h"
#include "callstack.h"
static uint64_t debugTime;
static uint64_t dumpTime = 0;
class MyFrame : public StackFrame<symbol_type> {
public:
void push(int stackLevel, uint64_t time, CallStackBase *base);
@@ -25,6 +28,8 @@ typedef CallStack<MyFrame> CallStackType;
void MyFrame::push(int stackLevel, uint64_t time, CallStackBase *base)
{
if (dumpTime > 0)
return;
printf("%llu en thr %d %3d", time, base->getId(), stackLevel);
for (int ii = 0; ii < stackLevel; ++ii)
printf(".");
@@ -33,6 +38,8 @@ void MyFrame::push(int stackLevel, uint64_t time, CallStackBase *base)
void MyFrame::pop(int stackLevel, uint64_t time, CallStackBase *base)
{
if (dumpTime > 0)
return;
printf("%llu x thr %d %3d", time, base->getId(), stackLevel);
for (int ii = 0; ii < stackLevel; ++ii)
printf(".");
@@ -43,8 +50,6 @@ static const int kNumStackFrames = 500;
static const int kMaxThreads = (32 * 1024);
CallStackType *stacks[kMaxThreads];
static uint64_t debugTime;
void Usage(const char *program)
{
fprintf(stderr, "Usage: %s [options] trace_name elf_file\n",
@@ -52,9 +57,29 @@ void Usage(const char *program)
OptionsUsage();
}
bool localParseOptions(int argc, char **argv)
{
bool err = false;
while (!err) {
int opt = getopt(argc, argv, "+d:");
if (opt == -1)
break;
switch (opt) {
case 'd':
dumpTime = strtoull(optarg, NULL, 0);
break;
default:
err = true;
break;
}
}
return err;
}
int main(int argc, char **argv)
{
ParseOptions(argc, argv);
localParseOptions(argc, argv);
if (argc - optind != 2) {
Usage(argv[0]);
exit(1);
@@ -66,9 +91,6 @@ int main(int argc, char **argv)
trace->Open(qemu_trace_file);
trace->ReadKernelSymbols(elf_file);
trace->SetRoot(root);
TraceHeader *qheader = trace->GetHeader();
uint64_t startTime = qheader->start_sec;
startTime = (startTime << 32) | qheader->start_usec;
BBEvent event;
while (1) {
@@ -93,6 +115,13 @@ int main(int argc, char **argv)
// Update the stack
pStack->updateStack(&event, function);
// If the user requested a stack dump at a certain time,
// and we are at that time, then dump the stack and exit.
if (dumpTime > 0 && event.time >= dumpTime) {
pStack->showStack(stdout);
break;
}
}
for (int ii = 0; ii < kMaxThreads; ++ii) {