• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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:
FunctionStack()39     FunctionStack() {
40         top = 0;
41     }
push(symbol_type * sym)42     void push(symbol_type *sym) {
43         if (top >= kNumStackFrames)
44             return;
45         frames[top] = sym;
46         top += 1;
47     }
48 
pop()49     symbol_type* pop() {
50         if (top <= 0) {
51             return NULL;
52         }
53         top -= 1;
54         return frames[top];
55     }
56 
showStack()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 
push(int stackLevel,uint64_t time,CallStackBase * base)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 
pop(int stackLevel,uint64_t time,CallStackBase * base)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 
Usage(const char * program)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 
main(int argc,char ** argv)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