1#include <stdio.h> 2#include <unistd.h> 3#include <stdlib.h> 4#include <string.h> 5#include <inttypes.h> 6#include "trace_reader.h" 7#include "parse_options.h" 8#include "opcode.h" 9 10const int kMillion = 1000000; 11const int kMHz = 200 * kMillion; 12 13struct symbol { 14 int numCalls; // number of times this function is called 15}; 16 17typedef TraceReader<symbol> TraceReaderType; 18 19#include "parse_options-inl.h" 20#include "callstack.h" 21 22class MyFrame : public StackFrame<symbol_type> { 23 public: 24 void push(int stackLevel, uint64_t time, CallStackBase *base) { 25 function->numCalls += 1; 26 } 27 void pop(int stackLevel, uint64_t time, CallStackBase *base) { 28 } 29}; 30 31typedef CallStack<MyFrame> CallStackType; 32 33static const int kNumStackFrames = 500; 34static const int kMaxThreads = (32 * 1024); 35CallStackType *stacks[kMaxThreads]; 36 37// This comparison function is called from qsort() to sort symbols 38// into decreasing number of calls. 39int cmp_sym_calls(const void *a, const void *b) { 40 const symbol_type *syma, *symb; 41 uint64_t calls1, calls2; 42 43 syma = static_cast<symbol_type const *>(a); 44 symb = static_cast<symbol_type const *>(b); 45 calls1 = syma->numCalls; 46 calls2 = symb->numCalls; 47 if (calls1 < calls2) 48 return 1; 49 if (calls1 == calls2) { 50 int cmp = strcmp(syma->name, symb->name); 51 if (cmp == 0) 52 cmp = strcmp(syma->region->path, symb->region->path); 53 return cmp; 54 } 55 return -1; 56} 57 58// This comparison function is called from qsort() to sort symbols 59// into alphabetical order. 60int cmp_sym_names(const void *a, const void *b) { 61 const symbol_type *syma, *symb; 62 63 syma = static_cast<symbol_type const *>(a); 64 symb = static_cast<symbol_type const *>(b); 65 int cmp = strcmp(syma->region->path, symb->region->path); 66 if (cmp == 0) 67 cmp = strcmp(syma->name, symb->name); 68 return cmp; 69} 70 71void Usage(const char *program) 72{ 73 fprintf(stderr, "Usage: %s [options] trace_file elf_file\n", program); 74 OptionsUsage(); 75} 76 77int main(int argc, char **argv) 78{ 79 ParseOptions(argc, argv); 80 if (argc - optind != 2) { 81 Usage(argv[0]); 82 exit(1); 83 } 84 85 char *trace_filename = argv[optind++]; 86 char *elf_file = argv[optind++]; 87 TraceReader<symbol> *trace = new TraceReader<symbol>; 88 trace->Open(trace_filename); 89 trace->SetDemangle(demangle); 90 trace->ReadKernelSymbols(elf_file); 91 trace->SetRoot(root); 92 93 BBEvent event; 94 while (1) { 95 BBEvent ignored; 96 symbol_type *function; 97 98 if (GetNextValidEvent(trace, &event, &ignored, &function)) 99 break; 100 if (event.bb_num == 0) 101 break; 102 103 // Get the stack for the current thread 104 CallStackType *pStack = stacks[event.pid]; 105 106 // If the stack does not exist, then allocate a new one. 107 if (pStack == NULL) { 108 pStack = new CallStackType(event.pid, kNumStackFrames, trace); 109 stacks[event.pid] = pStack; 110 } 111 112 // Update the stack 113 pStack->updateStack(&event, function); 114 } 115 116 for (int ii = 0; ii < kMaxThreads; ++ii) { 117 if (stacks[ii]) 118 stacks[ii]->popAll(event.time); 119 } 120 121 int nsyms; 122 symbol_type *syms = trace->GetSymbols(&nsyms); 123 124 // Sort the symbols into decreasing number of calls 125 qsort(syms, nsyms, sizeof(symbol_type), cmp_sym_names); 126 127 symbol_type *psym = syms; 128 for (int ii = 0; ii < nsyms; ++ii, ++psym) { 129 // Ignore functions with non-zero calls 130 if (psym->numCalls) 131 continue; 132 133 // Ignore some symbols 134 if (strcmp(psym->name, "(end)") == 0) 135 continue; 136 if (strcmp(psym->name, "(unknown)") == 0) 137 continue; 138 if (strcmp(psym->name, ".plt") == 0) 139 continue; 140 const char *ksym = " "; 141 if (psym->region->flags & region_type::kIsKernelRegion) 142 ksym = "k"; 143 printf("%s %s %s\n", ksym, psym->name, psym->region->path); 144#if 0 145 printf("#%d %5d %s %s %s\n", ii + 1, psym->numCalls, ksym, psym->name, 146 psym->region->path); 147#endif 148 } 149 delete[] syms; 150 delete trace; 151 152 return 0; 153} 154