Home | History | Annotate | Download | only in qtools
      1 // Copyright 2006 The Android Open Source Project
      2 
      3 #include <stdio.h>
      4 #include <unistd.h>
      5 #include <stdlib.h>
      6 #include <inttypes.h>
      7 #include <assert.h>
      8 #include "trace_reader.h"
      9 #include "bitvector.h"
     10 #include "parse_options.h"
     11 #include "dmtrace.h"
     12 #include "armdis.h"
     13 
     14 struct symbol {
     15     uint32_t id;
     16 };
     17 
     18 typedef TraceReader<symbol> TraceReaderType;
     19 
     20 #include "parse_options-inl.h"
     21 #include "callstack.h"
     22 
     23 DmTrace *dmtrace;
     24 
     25 class MyFrame : public StackFrame<symbol_type> {
     26   public:
     27     void push(int stackLevel, uint64_t time, CallStackBase *base);
     28     void pop(int stackLevel, uint64_t time, CallStackBase *base);
     29 };
     30 
     31 typedef CallStack<MyFrame> CallStackType;
     32 
     33 static const int kNumStackFrames = 500;
     34 static const int kMaxThreads = (32 * 1024);
     35 uint64_t thread_time[kMaxThreads];
     36 
     37 class FunctionStack {
     38   public:
     39     FunctionStack() {
     40         top = 0;
     41     }
     42     void push(symbol_type *sym) {
     43         if (top >= kNumStackFrames)
     44             return;
     45         frames[top] = sym;
     46         top += 1;
     47     }
     48 
     49     symbol_type* pop() {
     50         if (top <= 0) {
     51             return NULL;
     52         }
     53         top -= 1;
     54         return frames[top];
     55     }
     56 
     57     void showStack() {
     58         fprintf(stderr, "top %d\n", top);
     59         for (int ii = 0; ii < top; ii++) {
     60             fprintf(stderr, "  %d: %s\n", ii, frames[ii]->name);
     61         }
     62     }
     63 
     64   private:
     65     int top;
     66     symbol_type *frames[kNumStackFrames];
     67 };
     68 
     69 FunctionStack *dmtrace_stack[kMaxThreads];
     70 
     71 void MyFrame::push(int stackLevel, uint64_t time, CallStackBase *base)
     72 {
     73     int pid = base->getId();
     74     CallStackType *stack = (CallStackType *) base;
     75 
     76 #if 0
     77     fprintf(stderr, "native push t %llu p %d s %d fid %d 0x%x %s\n",
     78             stack->getGlobalTime(time), pid, stackLevel,
     79             function->id, function->addr, function->name);
     80 #endif
     81 
     82     FunctionStack *fstack = dmtrace_stack[pid];
     83     if (fstack == NULL) {
     84         fstack = new FunctionStack();
     85         dmtrace_stack[pid] = fstack;
     86     }
     87 
     88     fstack->push(function);
     89     thread_time[pid] = time;
     90     dmtrace->addFunctionEntry(function->id, time, pid);
     91 }
     92 
     93 void MyFrame::pop(int stackLevel, uint64_t time, CallStackBase *base)
     94 {
     95     int pid = base->getId();
     96     CallStackType *stack = (CallStackType *) base;
     97 
     98 #if 0
     99     fprintf(stderr, "native pop  t %llu p %d s %d fid %d 0x%x %s\n",
    100             stack->getGlobalTime(time), pid, stackLevel,
    101             function->id, function->addr, function->name);
    102 #endif
    103 
    104     FunctionStack *fstack = dmtrace_stack[pid];
    105     if (fstack == NULL) {
    106         fstack = new FunctionStack();
    107         dmtrace_stack[pid] = fstack;
    108     }
    109 
    110     symbol_type *sym = fstack->pop();
    111     if (sym != NULL && sym != function) {
    112         fprintf(stderr, "Error: q2dm function mismatch at time %llu pid %d sym %s\n",
    113                 stack->getGlobalTime(time), pid, sym->name);
    114         fstack->showStack();
    115         exit(1);
    116     }
    117 
    118     thread_time[pid] = time;
    119     dmtrace->addFunctionExit(function->id, time, pid);
    120 }
    121 
    122 uint32_t nextFunctionId = 4;
    123 CallStackType *stacks[kMaxThreads];
    124 
    125 void Usage(const char *program)
    126 {
    127     fprintf(stderr, "Usage: %s [options] trace_name elf_file dmtrace_name\n",
    128             program);
    129     OptionsUsage();
    130 }
    131 
    132 int main(int argc, char **argv)
    133 {
    134     bool useKernelStack = true;
    135 
    136     ParseOptions(argc, argv);
    137     if (argc - optind != 3) {
    138         Usage(argv[0]);
    139         exit(1);
    140     }
    141 
    142     char *qemu_trace_file = argv[optind++];
    143     char *elf_file = argv[optind++];
    144     char *dmtrace_file = argv[optind++];
    145     TraceReaderType *trace = new TraceReaderType;
    146     trace->Open(qemu_trace_file);
    147     trace->SetDemangle(demangle);
    148     trace->ReadKernelSymbols(elf_file);
    149     trace->SetRoot(root);
    150     TraceHeader *qheader = trace->GetHeader();
    151     uint64_t startTime = qheader->start_sec;
    152     startTime = (startTime << 32) | qheader->start_usec;
    153     int kernelPid = qheader->first_unused_pid;
    154 
    155     dmtrace = new DmTrace;
    156     dmtrace->open(dmtrace_file, startTime);
    157 
    158     bool inKernel = false;
    159     CallStackType *kernelStack = NULL;
    160     if (useKernelStack) {
    161         // Create a fake kernel thread stack where we will put all the kernel
    162         // code.
    163         kernelStack = new CallStackType(kernelPid, kNumStackFrames, trace);
    164         dmtrace->addThread(kernelPid, "(kernel)");
    165     }
    166 
    167     CallStackType *prevStack = NULL;
    168     BBEvent event;
    169     while (1) {
    170         BBEvent ignored;
    171         symbol_type *function;
    172 
    173         if (GetNextValidEvent(trace, &event, &ignored, &function))
    174             break;
    175         if (event.bb_num == 0)
    176             break;
    177 #if 0
    178         fprintf(stderr, "event t %llu p %d %s\n",
    179                 event.time, event.pid, function->name);
    180 #endif
    181 
    182         CallStackType *pStack;
    183         if (useKernelStack) {
    184             uint32_t flags = function->region->flags;
    185             uint32_t region_mask = region_type::kIsKernelRegion
    186                     | region_type::kIsUserMappedRegion;
    187             if ((flags & region_mask) == region_type::kIsKernelRegion) {
    188                 // Use the kernel stack
    189                 pStack = kernelStack;
    190                 inKernel = true;
    191             } else {
    192                 // If we were just in the kernel then pop off all of the
    193                 // stack frames for the kernel thread.
    194                 if (inKernel == true) {
    195                     inKernel = false;
    196                     kernelStack->popAll(event.time);
    197                 }
    198 
    199                 // Get the stack for the current thread
    200                 pStack = stacks[event.pid];
    201             }
    202         } else {
    203             // Get the stack for the current thread
    204             pStack = stacks[event.pid];
    205         }
    206 
    207         // If the stack does not exist, then allocate a new one.
    208         if (pStack == NULL) {
    209             pStack = new CallStackType(event.pid, kNumStackFrames, trace);
    210             stacks[event.pid] = pStack;
    211             const char *name = trace->GetProcessName(event.pid);
    212             dmtrace->addThread(event.pid, name);
    213         }
    214 
    215         if (prevStack != pStack) {
    216             pStack->threadStart(event.time);
    217             if (prevStack)
    218                 prevStack->threadStop(event.time);
    219         }
    220         prevStack = pStack;
    221 
    222         // If we have never seen this function before, then add it to the
    223         // list of known functions.
    224         if (function->id == 0) {
    225             function->id = nextFunctionId;
    226             nextFunctionId += 4;
    227             uint32_t flags = function->region->flags;
    228             const char *name = function->name;
    229             if (flags & region_type::kIsKernelRegion) {
    230                 // To distinguish kernel function names from user library
    231                 // names, add a marker to the name.
    232                 int len = strlen(name) + strlen(" [kernel]") + 1;
    233                 char *kernelName = new char[len];
    234                 strcpy(kernelName, name);
    235                 strcat(kernelName, " [kernel]");
    236                 name = kernelName;
    237             }
    238             dmtrace->parseAndAddFunction(function->id, name);
    239         }
    240 
    241         // Update the stack
    242         pStack->updateStack(&event, function);
    243     }
    244 
    245     if (prevStack == NULL) {
    246         fprintf(stderr, "Error: no events in trace.\n");
    247         exit(1);
    248     }
    249     prevStack->threadStop(event.time);
    250     for (int ii = 0; ii < kMaxThreads; ++ii) {
    251         if (stacks[ii]) {
    252             stacks[ii]->threadStart(event.time);
    253             stacks[ii]->popAll(event.time);
    254         }
    255     }
    256     if (useKernelStack) {
    257         kernelStack->popAll(event.time);
    258     }
    259 
    260     // Read the pid events to find the names of the processes
    261     while (1) {
    262         PidEvent pid_event;
    263         if (trace->ReadPidEvent(&pid_event))
    264             break;
    265         if (pid_event.rec_type == kPidName) {
    266             dmtrace->updateName(pid_event.pid, pid_event.path);
    267         }
    268     }
    269 
    270     dmtrace->close();
    271     delete dmtrace;
    272     delete trace;
    273     return 0;
    274 }
    275