Home | History | Annotate | Download | only in qtools
      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 
     10 const int kMillion = 1000000;
     11 const int kMHz = 200 * kMillion;
     12 
     13 struct symbol {
     14     int    numCalls;    // number of times this function is called
     15 };
     16 
     17 typedef TraceReader<symbol> TraceReaderType;
     18 
     19 #include "parse_options-inl.h"
     20 #include "callstack.h"
     21 
     22 class 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 
     31 typedef CallStack<MyFrame> CallStackType;
     32 
     33 static const int kNumStackFrames = 500;
     34 static const int kMaxThreads = (32 * 1024);
     35 CallStackType *stacks[kMaxThreads];
     36 
     37 // This comparison function is called from qsort() to sort symbols
     38 // into decreasing number of calls.
     39 int 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.
     60 int 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 
     71 void Usage(const char *program)
     72 {
     73     fprintf(stderr, "Usage: %s [options] trace_file elf_file\n", program);
     74     OptionsUsage();
     75 }
     76 
     77 int 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